web-dev-qa-db-ja.com

使用するアノテーション:@IdClassまたは@EmbeddedId

JPA(Java Persistence API)仕様には、エンティティ複合キーを指定する2つの異なる方法があります:@IdClassおよび@EmbeddedId

マップされたエンティティで両方の注釈を使用していますが、JPAにあまり詳しくない人にとっては大きな混乱になることがわかりました。

複合キーを指定する方法を1つだけ採用したい。どれが本当に最高ですか?どうして?

116
sakana

@EmbeddedIdでは、フィールドアクセス演算子を使用して主キーオブジェクト全体にアクセスできないため、@IdClassはおそらくより冗長であると考えます。 @EmbeddedIdを使用すると、次のようにできます。

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

これは、フィールドアクセス演算子を介してアクセスされるクラスにすべて集約されるため、複合キーを作成するフィールドの明確な概念を提供します。

@IdClass@EmbeddedIdのもう1つの違いは、HQLを作成するときです。

@IdClassを使用して次のように記述します。

従業員eからe.nameを選択します

@EmbeddedIdを使用すると、次のように記述する必要があります。

従業員eからe.employeeId.nameを選択します

同じクエリに対してより多くのテキストを記述する必要があります。これは、IdClassによって促進されるようなより自然な言語とは異なると主張する人もいるかもしれません。しかし、ほとんどの場合、特定のフィールドが複合キーの一部であることをクエリから理解することは非常に役立ちます。

80
Jorge Ferreira

IdClassの代わりにEmbeddedIdを使用する必要があるインスタンスを発見しました。このシナリオには、追加の列が定義された結合テーブルがあります。 IdClassを使用してこの問題を解決し、結合テーブルの行を明示的に表すエンティティのキ​​ーを表現しようとしました。この方法で動作させることはできませんでした。ありがたいことに「Java Persistence With Hibernate」には、このトピック専用のセクションがあります。提案されたソリューションの1つは、私のものと非常に似ていましたが、代わりにEmbeddedIdを使用しました。オブジェクトを本の中でモデル化して、今では正しく動作するようになりました。

17
laz

複合主キーを使用するには、次の3つの戦略があります。

  • @Embeddableとしてマークし、エンティティクラスに@Idでマークされた通常のプロパティを追加します。
  • エンティティクラスに、@EmbeddedIdでマークされた通常のプロパティを追加します。
  • すべてのフィールドのエンティティクラスにプロパティを追加し、@Idでマークし、@IdClassでエンティティクラスをマークして、主キークラスのクラスを指定します。

@Idとマークされたクラスで@Embeddableを使用するのが最も自然なアプローチです。 @Embeddableタグは、とにかく非プライマリキーの埋め込み可能な値に使用できます。複合主キーを単一のプロパティとして扱うことができ、他のテーブルで@Embeddableクラスを再利用できます。

次に自然なアプローチは、@EmbeddedIdタグの使用です。ここでは、主キークラスは@Embeddableエンティティではないため、他のテーブルでは使用できませんが、キーをあるクラスの単一の属性として扱うことができます。

最後に、@IdClassおよび@Idアノテーションを使用すると、プライマリキークラスのプロパティの名前に対応するエンティティ自体のプロパティを使用して、複合プライマリキークラスをマップできます。名前は対応している必要があり(これをオーバーライドするメカニズムはありません)、主キークラスは他の2つの手法と同じ義務を果たす必要があります。このアプローチの唯一の利点は、主エンティティを含むエンティティのインターフェイスから主キークラスの使用を「隠す」機能です。 @IdClassアノテーションは、クラスタイプの値パラメーターを取ります。これは、複合主キーとして使用されるクラスでなければなりません。使用する主キークラスのプロパティに対応するフィールドには、すべて@Idの注釈を付ける必要があります。

参照: http://www.apress.com/us/book/9781430228509

15
Adelin

私の知る限り、コンポジットPKにFKが含まれている場合、@IdClassを使用する方が簡単で簡単です

@EmbeddedIdを使用すると、FK列のマッピングを2回、@Embeddedableに1回、そして@ManyToOneに1回、@ManyToOneを読み取り専用にする必要があります(@PrimaryKeyJoinColumn)1つの列を2つの変数に設定することはできないため(競合の可能性)。
したがって、@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;
    }
}
12
Ondrej Bozek

主な利点は、@GeneratedValueを使用するときにIDに@IdClassを使用できることです。 @GeneratedValue@EmbeddedIdを使用できないと確信しています。

7
bertie

@Idを使用する場合、複合キーに@EmbeddedIdプロパティを含めることはできません。

4
B.K

EmbeddedIdを使用すると、HQLでIN句を使用できます。例:FROM Entity WHERE id IN :ids idはEmbeddedIdですが、IdClassで同じ結果を達成するのは苦痛ですが、FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

1
Aleks Ben Maza