どのアノテーションを使用する必要がありますか:@IdClassまたは@EmbeddedId


128

JPA(れるJava Persistence API)仕様では、エンティティ複合キーを指定するための2種類の方法があります@IdClass@EmbeddedId

マッピングされたエンティティで両方のアノテーションを使用していますが、にあまり詳しくない人にとっては大きな混乱になることがわかりましたJPA

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

回答:


86

では、フィールドアクセス演算子を使用して主キーオブジェクト全体にアクセスすることはできない@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ます。しかし、ほとんどの場合、特定のフィールドが複合キーの一部であることをクエリから正しく理解することは、非常に役立ちます。


10
上記の説明に同意しますが、ほとんどの状況で@IdClass私が好みますが、ユニークなユースケースを1つ追加したいと思います@EmbeddedId(Antonio Goncalvesのセッションからこれを知るようになりました。彼が提案したことは@IdClass、キークラスはアクセスできないか、これらのシナリオは、.IN我々は注釈を追加することはできません別のモジュールまたはレガシーコードから入って来@IdClass私たちの道私たちを与えるだろう。
のGaurav Rawat

1
私はそれが使用するための例という可能性だと思う@IdClass@Gauravによって指定された注釈は、JPA仕様のリスト複合キーを作成するための両方の方法それは非常に理由..です@IdClass@EmbeddidId
kapad

20

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

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

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

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

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

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


17

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


13

私の知る限り、複合PKにFKが含まれている場合は、使用する方が簡単で簡単です @IdClass

では@EmbeddedId、あなたは、二回でoneceあなたのFKの列のマッピングを定義する必要が@Embeddedableすなわちとしてのために、一度@ManyToOneどこ@ManyToOne(読み取り専用する必要があり@PrimaryKeyJoinColumnます2つの変数(競合の可能性)での1つの列セットを持つことができないために)。
したがって、で単純型を使用してFKを設定する必要があります@Embeddedable

OneToOneおよびManyToOne関係を介し@IdClass主キーに示すように、この状況を使用する他のサイトでは、はるかに簡単に処理できます。

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;
    }
}

1
PKクラスにゲッターを追加するのを忘れないでください
Sonata

@ソナタなぜゲッターが必要なのですか?ゲッター/セッターなしで試してみましたが、
正常

idクラスの例をありがとう!最終的にはSerializableも実装する必要がありました。特にIDEが自動的に生成できる場合は、ゲッターとセッターを追加することもできます。
Starwarswii

8

主な利点は@GeneratedValue@IdClass?を使用するときにidに使用できることです。私は、我々が使用することはできません確信している@GeneratedValueため@EmbeddedId


1
Embeddedidで@GeneratedValueを使用することはできませんか?
Kayser 2012年

1
EmbeddedIdでうまく使用しましたが、サポートはDBによって異なります。これは、IdClassで使用する場合にも当てはまります。仕様によると、「GeneratedValueアノテーションは、単純な(つまり、非複合の)主キーに対してのみ移植可能に使用できます。」
BPS

4

を使用する@Id場合、複合キーにプロパティがあって@EmbeddedIdはなりません。


1

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.