Kann mir bitte jemand @MapsId im Ruhezustand erklären?

79

Kann mir bitte jemand @MapsIdim Winterschlaf erklären ? Es fällt mir schwer, das zu verstehen.

Es wäre großartig, wenn man es anhand eines Beispiels erklären könnte und in welchen Anwendungsfällen ist es am besten anwendbar?

Brainydexter
quelle

Antworten:

46

Hier ist eine schöne Erklärung von Object DB .

Bezeichnet ein ManyToOne- oder OneToOne-Beziehungsattribut, das die Zuordnung für einen EmbeddedId-Primärschlüssel, ein Attribut innerhalb eines EmbeddedId-Primärschlüssels oder einen einfachen Primärschlüssel der übergeordneten Entität bereitstellt. Das value-Element gibt das Attribut in einem zusammengesetzten Schlüssel an, dem das Beziehungsattribut entspricht. Wenn der Primärschlüssel der Entität vom selben Java-Typ ist wie der Primärschlüssel der Entität, auf die in der Beziehung verwiesen wird, wird das Wertattribut nicht angegeben.

// parent entity has simple primary key

@Entity
public class Employee {
   @Id long empId;
   String name;
   ...
} 

// dependent entity uses EmbeddedId for composite key

@Embeddable
public class DependentId {
   String name;
   long empid;   // corresponds to primary key type of Employee
}

@Entity
public class Dependent {
   @EmbeddedId DependentId id;
    ...
   @MapsId("empid")  //  maps the empid attribute of embedded id
   @ManyToOne Employee emp;
}

Lesen Sie hier die API-Dokumente .

ManuPK
quelle
6
Aber was ist daran so schön? Auch ohne @MapsId kann man JoinColumn mit demselben Effekt verwenden, nicht wahr? Und wenn ja, sagt dieses Beispiel nicht wirklich, wofür diese Anmerkung wirklich gut ist.
Maksim Gumerov
2
Da beide Entitäten denselben Primärschlüssel verwenden, hat die Entität mit einer durch @MapsIdwill in der Persistenzschicht (Datenbank) bezeichneten Spalte nur eine Primärschlüsselspalte. Die Idee ist, den Primärschlüssel zwischen den beiden Entitäten zu teilen.
Johanwannheden
Was ist ein EmbeddedId-Primärschlüssel? Wie unterscheidet es sich vom normalen Primärschlüssel?
sofs1
"Das Wertelement gibt das Attribut in einem zusammengesetzten Schlüssel an, dem das Beziehungsattribut entspricht." 1) Was ist mit Wertelement gemeint, geben Sie bitte ein Beispiel an? 2) Was ist ein zusammengesetzter Schlüssel? 3) Was ist das Beziehungsattribut und geben Sie ein Beispiel?
sofs1
@MaksimGumerov ist effizient, weil Sie Dependentnur durch Kenntnis der Kennung von abrufen können Employee.
Emmanuel Osimosu
24

Ich fand diesen Hinweis auch nützlich: @MapsIdIm Ruhezustand ordnet Annotation eine Spalte der Spalte einer anderen Tabelle zu.

Es kann auch verwendet werden, um denselben Primärschlüssel zwischen zwei Tabellen zu teilen.

Beispiel:

@Entity
@Table(name = "TRANSACTION_CANCEL")
public class CancelledTransaction {
    @Id
    private Long id; // the value in this pk will be the same as the
                     // transaction line from transaction table to which 
                     // this cancelled transaction is related

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_TRANSACTION", nullable = false)
    @MapsId
    private Transaction transaction;
    ....
}

@Entity
@Table(name = "TRANSACTION")
@SequenceGenerator(name = "SQ_TRAN_ID", sequenceName = "SQ_TRAN_ID")
public class Transaction  {
    @Id
    @GeneratedValue(generator = "SQ_TRAN_ID", strategy = GenerationType.SEQUENCE)
    @Column(name = "ID_TRANSACTION", nullable = false)
    private Long id;
    ...
}
Tonsic
quelle
Wo lege ich @MapsId in eine bidirektionale Zuordnung? Sollten beide Klassen haben @MapsId. Macht es überhaupt einen Unterschied?
Marcus
Ich denke, eine Tabelle wird der "Besitzer" des ursprünglichen Pakets sein (die mit @Idund @GeneratedValueund @Column) und ein @OneToOneund @JoinColumnmit der anderen Tabelle haben, und die andere Tabelle wird die haben @MapsId. Dies würde jedoch wahrscheinlich nicht funktionieren, wenn Sie zuerst in die 'andere Tabelle' EINFÜGEN möchten.
Tonsic
1
Ein netter Artikel über diese Art der Verwendung (Verwendung der ID aus einer anderen Tabelle als ID einer anderen Entität) ist hier vladmihalcea.com/…
Lubo
Aber wenn Sie Transaktionen aus stornierten herausfiltern möchten, ist dies eine häufige Ursache. Wie ist das effizienter? Ich meine, für SQL muss man für TRANSACTION.fk_cancelled_id nur NOT NULL sagen, aber in diesem Fall werden es mehr Operationen sein.
M_F
In diesem speziellen Fall wird hier häufig eine Spalte wie "Typ" in der Basisklasse und Tabelle verwendet, in der angegeben wird, ob die Transaktion vom Typ "Abbrechen" oder einer anderen ist.
Tonsic
2

Wie er Vladimir in seinem Tutorial erklärte , ist die Verwendung von @MapsId der beste Weg, eine @ OneToOne-Beziehung abzubilden. Auf diese Weise benötigen Sie nicht einmal eine bidirektionale Zuordnung, da Sie die untergeordnete Entität jederzeit mithilfe der übergeordneten Entitätskennung abrufen können.

BERGUIGA Mohamed Amine
quelle
2

Mit MapsId können Sie denselben Primärschlüssel zwischen zwei verschiedenen Entitäten / Tabellen verwenden. Hinweis: Wenn Sie MapsId verwenden, wird das CASCADE.ALLFlag unbrauchbar und Sie müssen sicherstellen, dass Ihre Entitäten manuell gespeichert werden.

Janac Meena
quelle
1

IMHO, der beste Weg, um darüber nachzudenken @MapsId wenn Sie einen zusammengesetzten Schlüssel in einer: m-Entität zuordnen müssen.

Zum Beispiel kann ein Kunde einen oder mehrere Berater haben und ein Berater kann einen oder mehrere Kunden haben:

Geben Sie hier die Bildbeschreibung ein

Und Ihre Entitäten wären ungefähr so ​​(Pseudo-Java-Code):

@Entity
public class Customer {
   @Id
   private Integer id;

   private String name;
}

@Entity
public class Consultant {
   @Id
   private Integer id;

   private String name;

   @OneToMany
   private List<CustomerByConsultant> customerByConsultants = new ArrayList<>();

   public void add(CustomerByConsultant cbc) {
      cbc.setConsultant(this);
      this.customerByConsultant.add(cbc);
   }
}

@Embeddable
public class ConsultantByConsultantPk implements Serializable {

    private Integer customerId;

    private Integer consultantId;
}

@Entity
public class ConsultantByConsultant {

   @EmbeddedId
   private ConsultantByConsultantPk id = new ConsultantByConsultantPk();

   @MapsId("customerId")
   @JoinColumn(insertable = false, updatable = false)
   Customer customer;

   @MapsId("consultantId")
   @JoinColumn(insertable = false, updatable = false)
   Consultant consultant;
}

Auf diese Weise fügt JPA automatisch Customerund ConsultantIDs ein, EmbeddableIdwenn Sie einen Berater speichern. Sie müssen das also nicht manuell erstellen ConsultantByConsultantPk.

Jaumzera
quelle