Welche Anmerkung soll ich verwenden: @IdClass oder @EmbeddedId

128

Die JPASpezifikation (Java Persistence API) bietet zwei verschiedene Möglichkeiten, um zusammengesetzte Entitätsschlüssel anzugeben: @IdClassund @EmbeddedId.

Ich verwende beide Anmerkungen für meine zugeordneten Entitäten, aber für Leute, die nicht sehr vertraut sind, stellt sich heraus, dass dies ein großes Durcheinander ist JPA.

Ich möchte nur einen Weg wählen, um zusammengesetzte Schlüssel anzugeben. Welches ist wirklich das Beste? Warum?

Sakana
quelle

Antworten:

86

Ich halte das @EmbeddedIdwahrscheinlich für ausführlicher, da @IdClassSie mit keinem Feldzugriffsoperator auf das gesamte Primärschlüsselobjekt zugreifen können. Mit dem können @EmbeddedIdSie Folgendes tun:

@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
  @EmbeddedId EmployeeId employeeId;
  ...
}

Dies gibt eine klare Vorstellung von den Feldern, aus denen der zusammengesetzte Schlüssel besteht, da sie alle in einer Klasse zusammengefasst sind, auf die über einen Feldzugriffsoperator zugegriffen wird.

Ein weiterer Unterschied zu @IdClassund @EmbeddedIdist, wenn es darum geht, HQL zu schreiben:

Mit @IdClassdir schreiben:

Wählen Sie e.name aus Mitarbeiter e

und mit @EmbeddedIddir muss schreiben:

Wählen Sie e.employeeId.name aus Employee e

Sie müssen mehr Text für dieselbe Abfrage schreiben. Einige mögen argumentieren, dass sich dies von einer natürlicheren Sprache wie der von unterscheidet IdClass. In den meisten Fällen ist es jedoch von unschätzbarem Wert, direkt anhand der Abfrage zu verstehen, dass ein bestimmtes Feld Teil des zusammengesetzten Schlüssels ist.

Jorge Ferreira
quelle
10
Obwohl ich der oben gegebenen Erklärung zustimme, möchte ich auch einen einzigartigen Anwendungsfall hinzufügen, @IdClassauch wenn ich dies @EmbeddedIdin den meisten Situationen bevorzuge ( Ich habe dies aus einer Sitzung von Antonio Goncalves erfahren. Er schlug vor, dass wir den @IdClassFall für den Fall des Komposits verwenden könnten Schlüsselklasse ist nicht zugänglich oder kommt von einem anderen Modul oder Legacy-Code, wo wir keine Annotation hinzufügen können. In diesen Szenarien @IdClassgeben uns einen Weg unsere.
Gaurav Rawat
1
Ich denke, es ist möglich, dass die Fälle für die Verwendung der @IdClassvon @Gaurav angegebenen Annotation genau der Grund sind, warum die JPA-Spezifikation beide Methoden zum Erstellen eines zusammengesetzten Schlüssels @IdClass@EmbeddidId
auflistet
20

Es gibt drei Strategien zur Verwendung eines zusammengesetzten Primärschlüssels:

  • Markieren Sie es als @Embeddableund fügen Sie Ihrer Entitätsklasse eine normale Eigenschaft hinzu, die mit markiert ist @Id.
  • Fügen Sie Ihrer Entitätsklasse eine normale Eigenschaft hinzu, die mit gekennzeichnet ist @EmbeddedId.
  • Fügen Sie Ihrer Entitätsklasse Eigenschaften für alle Felder hinzu, markieren Sie sie mit @Idund markieren Sie Ihre Entitätsklasse mit @IdClass, indem Sie die Klasse Ihrer Primärschlüsselklasse angeben.

Die Verwendung @Idmit einer Klasse, die als markiert @Embeddableist, ist der natürlichste Ansatz. Das @EmbeddableTag kann ohnehin für nicht in Primärschlüssel einbettbare Werte verwendet werden. Sie können den zusammengesetzten Primärschlüssel als eine einzelne Eigenschaft behandeln und die @EmbeddableKlasse in anderen Tabellen wiederverwenden .

Der nächst natürlichste Ansatz ist die Verwendung des @EmbeddedIdTags. Hier kann die Primärschlüsselklasse nicht in anderen Tabellen verwendet werden, da es sich nicht um eine @EmbeddableEntität handelt. Sie ermöglicht es uns jedoch, den Schlüssel als einzelnes Attribut einer Klasse zu behandeln.

Schließlich ermöglicht die Verwendung der Annotationen @IdClassund die @IdAnnotation der zusammengesetzten Primärschlüsselklasse unter Verwendung der Eigenschaften der Entität selbst, die den Namen der Eigenschaften in der Primärschlüsselklasse entsprechen. Die Namen müssen übereinstimmen (es gibt keinen Mechanismus, um dies zu überschreiben), und die Primärschlüsselklasse muss die gleichen Verpflichtungen wie bei den beiden anderen Techniken erfüllen. Der einzige Vorteil dieses Ansatzes ist seine Fähigkeit, die Verwendung der Primärschlüsselklasse vor der Schnittstelle der einschließenden Entität zu "verbergen". Die @IdClassAnnotation verwendet einen Wertparameter vom Typ Klasse, der die Klasse sein muss, die als zusammengesetzter Primärschlüssel verwendet werden soll. Die Felder, die den Eigenschaften der zu verwendenden Primärschlüsselklasse entsprechen, müssen alle mit Anmerkungen versehen sein @Id.

Referenz: http://www.apress.com/us/book/9781430228509

Adelin
quelle
17

Ich habe eine Instanz entdeckt, in der ich EmbeddedId anstelle von IdClass verwenden musste. In diesem Szenario gibt es eine Verknüpfungstabelle, in der zusätzliche Spalten definiert sind. Ich habe versucht, dieses Problem mithilfe von IdClass zu lösen, um den Schlüssel einer Entität darzustellen, die explizit Zeilen in der Join-Tabelle darstellt. Ich konnte es nicht so zum Laufen bringen. Zum Glück hat "Java Persistence With Hibernate" einen Abschnitt, der diesem Thema gewidmet ist. Eine vorgeschlagene Lösung war meiner sehr ähnlich, verwendete jedoch stattdessen EmbeddedId. Ich habe meine Objekte nach denen im Buch modelliert, die sich jetzt korrekt verhalten.

laz
quelle
13

Soweit ich weiß, ist es einfacher und unkomplizierter, wenn Ihre zusammengesetzte PK FK enthält @IdClass

Mit müssen @EmbeddedIdSie die Zuordnung für Ihre FK-Spalte zweimal definieren, einmal @Embeddedableund einmal für, dh @ManyToOnewo @ManyToOnemuss schreibgeschützt sein ( @PrimaryKeyJoinColumn), da Sie nicht eine Spalte in zwei Variablen festlegen können (mögliche Konflikte).
Sie müssen also Ihre FK durch einfaches Eingeben einstellen @Embeddedable.

Auf der anderen Site kann die Verwendung @IdClassdieser Situation viel einfacher gehandhabt werden, wie in Primärschlüssel über OneToOne- und ManyToOne-Beziehungen gezeigt :

Beispiel für eine JPA 2.0 ManyToOne-ID-Annotation

...
@Entity
@IdClass(PhonePK.class)
public class Phone {

    @Id
    private String type;

    @ManyToOne
    @Id
    @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
    private Employee owner;
    ...
}

Beispiel für eine JPA 2.0-ID-Klasse

...
public class PhonePK {
    private String type;
    private long owner;

    public PhonePK() {}

    public PhonePK(String type, long owner) {
        this.type = type;
        this.owner = owner;
    }

    public boolean equals(Object object) {
        if (object instanceof PhonePK) {
            PhonePK pk = (PhonePK)object;
            return type.equals(pk.type) && owner == pk.owner;
        } else {
            return false;
        }
    }

    public int hashCode() {
        return type.hashCode() + owner;
    }
}
Ondrej Bozek
quelle
1
Vergessen Sie nicht, Ihrer PK-Klasse Getter hinzuzufügen
Sonata
@ Sonata warum brauchen wir die Getter? Ich habe es ohne Getter / Setter versucht und es funktioniert gut
Xagaffar
Danke für das Beispiel der ID-Klasse! Obwohl ich letztendlich auch Serializable implementieren musste. Sie können auch Getter und Setter hinzufügen, insbesondere wenn Ihre IDE diese automatisch generieren kann.
Starwarswii
8

Ich denke, der Hauptvorteil ist, dass wir @GeneratedValuefür die ID verwenden könnten, wenn wir das @IdClass? Ich bin sicher, wir können nicht @GeneratedValuefür verwenden @EmbeddedId.

Bertie
quelle
1
Ist es nicht möglich, @GeneratedValue in Embeddedid zu verwenden?
Kayser
1
Ich habe es erfolgreich mit EmbeddedId verwendet, aber anscheinend variiert die Unterstützung je nach Datenbank. Dies gilt auch für die Verwendung mit IdClass. In der Spezifikation heißt es: "Die Annotation GeneratedValue darf nur für einfache (dh nicht zusammengesetzte) Primärschlüssel portabel verwendet werden."
BPS
4

Der zusammengesetzte Schlüssel darf bei Verwendung keine @IdEigenschaft haben @EmbeddedId.

BK
quelle
1

Mit EmbeddedId können Sie die IN-Klausel in HQL verwenden, zum Beispiel: FROM Entity WHERE id IN :idswobei id eine EmbeddedId ist, während es schwierig ist, mit IdClass dasselbe Ergebnis zu erzielen, wie Sie es möchtenFROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

Aleks Ben Maza
quelle