どの注釈を使用すればよいですか:@IdClass または @EmbeddedId
-
03-07-2019 - |
質問
の JPA
(Java Persistence API) 仕様には、エンティティ複合キーを指定する 2 つの異なる方法があります。 @IdClass
そして @EmbeddedId
.
マップされたエンティティに両方の注釈を使用していますが、あまり慣れていない人にとっては非常に混乱することがわかりました。 JPA
.
複合キーの指定方法は1つだけ採用したいと考えています。本当にどれが一番いいのでしょうか?なぜ?
解決
@IdClass
では、フィールドアクセス演算子を使用して主キーオブジェクト全体にアクセスできないため、 @EmbeddedId
はおそらくより冗長だと思います。 @EmbeddedId
を使用すると、次のようにできます。
@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
@EmbeddedId EmployeeId employeeId;
...
}
これは、フィールドアクセス演算子を介してアクセスされるクラスにすべて集約されるため、複合キーを作成するフィールドの明確な概念を提供します。
@IdClass
と @EmbeddedId
のもう1つの違いは、HQLの記述に関してです:
@IdClass
を使用して次のように記述します。
select e.name from Employee e
および @EmbeddedId
を使用して記述する必要があります:
select e.employeeId.name from Employee e
同じクエリに対してより多くのテキストを記述する必要があります。これは、 IdClass
によって促進されるようなより自然な言語とは異なると主張する人もいるかもしれません。しかし、ほとんどの場合、クエリから特定のフィールドが複合キーの一部であることを理解することは、非常に貴重です。
他のヒント
IdClass の代わりに EmbeddedId を使用する必要があるインスタンスを発見しました。このシナリオでは、追加の列が定義された結合テーブルがあります。私は、結合テーブル内の行を明示的に表すエンティティのキーを表す IdClass を使用して、この問題を解決しようとしました。この方法ではうまくいきませんでした。ありがたいことに、「Java Persistence With Hibernate」には、このトピック専用のセクションがあります。提案されたソリューションの 1 つは私と非常に似ていましたが、代わりに EmbeddedId を使用していました。本のオブジェクトに基づいてオブジェクトをモデル化したところ、正しく動作するようになりました。
複合主キーを使用するには、次の3つの戦略があります。
-
@Embeddable
としてマークし、@Id
でマークされた通常のプロパティをエンティティクラスに追加します。 -
@EmbeddedId
でマークされた通常のプロパティをエンティティクラスに追加します。 - すべてのフィールドのエンティティクラスにプロパティを追加し、それらを
@Id
でマークし、エンティティクラスを@IdClass
でマークして、プライマリのクラスを提供しますキークラス。
@Embeddable
とマークされたクラスで @Id
を使用するのが最も自然なアプローチです。 @Embeddable
タグは、非プライマリキーの埋め込み可能な値に使用できます。複合主キーを単一のプロパティとして扱うことができ、 @Embeddable
クラスを他のテーブルで再利用できます。
次に最も自然なアプローチは、 @EmbeddedId
タグの使用です。ここでは、プライマリキークラスは @Embeddable
エンティティではないため、他のテーブルでは使用できませんが、キーを
あるクラスの単一の属性。
最後に、 @IdClass
および @Id
注釈を使用すると、エンティティの名前に対応するエンティティ自体のプロパティを使用して、複合主キークラスをマッピングできます。主キークラスのプロパティ。名前は対応している必要があり(これをオーバーライドするメカニズムはありません)、主キークラスは他の2つの手法と同じ義務を果たす必要があります。このアプローチの唯一の利点は、“非表示”囲んでいるエンティティのインターフェースからの主キークラスの使用。 @IdClass
アノテーションは、クラスタイプの値パラメーターを取ります。これは、複合主キーとして使用されるクラスでなければなりません。使用する主キークラスのプロパティに対応するフィールドには、すべて @Id
の注釈を付ける必要があります。
複合PKにFKが含まれているかどうかを知る限り、 @IdClass
@EmbeddedId
では、FK列のマッピングを2回定義し、 @Embeddedable
に1回、 @ManyToOne
に1回定義する必要があります。 @ManyToOne
は読み取り専用( @PrimaryKeyJoinColumn
)である必要があります。2つの変数に1つの列を設定できない(競合の可能性がある)。
そのため、 @Embeddedable
の単純なタイプを使用してFKを設定する必要があります。
@IdClass
を使用する他のサイトでは、 OneToOneおよびManyToOne関係によるプライマリキー:
JPA 2.0 ManyToOne idアノテーションの例
...
@Entity
@IdClass(PhonePK.class)
public class Phone {
@Id
private String type;
@ManyToOne
@Id
@JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
private Employee owner;
...
}
JPA 2.0 idクラスの例
...
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;
}
}
主な利点は、 @IdClass
を使用するときにidに @GeneratedValue
を使用できることだと思いますか? @EmbeddedId
に @GeneratedValue
を使用できないと確信しています。
@EmbeddedId
を使用する場合、 Composite Keyに @Id
プロパティを含めることはできません。
EmbeddedIdを使用すると、HQLでIN句を使用できます。例: FROM Entity WHERE id IN:ids
idはEmbeddedIdですが、IdClassで同じ結果を得るのは面倒です FROMエンティティWHERE idPartA =:idPartA0 AND idPartB =:idPartB0 .... OR idPartA =:idPartAN AND idPartB =:idPartBN