web-dev-qa-db-ja.com

JPAエンティティにequals()およびhashCode()メソッドを記述する必要がありますか?

エンティティがコレクションメンバーにあるかどうかを確認したい(@OneToManyまたは@ManyToMany)別のエンティティ:

if (entity2.getEntities1().contains(entity1)) { }
55
j2j

必ずしも。次の3つのオプションがあります。

  • オーバーライドしないでください-したがって、インスタンスを操作します。これは、セッションにアタッチされているエンティティのみでコレクションを操作している場合(したがって、同じインスタンスであることが保証されている場合)には問題ありません。多くの場合、これは(私にとって)好ましい方法です。オーバーライドする際に必要なコードと考慮事項が少ないためです。

  • hashCode()およびequals()をビジネスキーでオーバーライドします。それは、エンティティを識別するプロパティのサブセットである場合があります。たとえば、Userの場合、適切なビジネスキーはusernameまたはemailです。これは良い習慣と見なされます。

  • iDフィールドのみを使用して、hashCode()およびequals()をオーバーライドします。これは、特に手動で割り当てられた識別子(UUIDなど)がある場合は特に問題ありません。エンティティがコレクションに決して入らない場合も問題ありません。ただし、コレクションに入る一時的なエンティティ(識別子なし)の場合、問題が発生するため、このオプションには注意が必要です。 seanizerが指摘したように-あなたはそれを避けるべきです。一般的に、常に、あなたが何をしているのかを本当に知っていない限り(そして、おそらくそれを文書化する)

この記事を参照 詳細については。また、equals()hashCode()は結び付けられており、両方ともまったく同じフィールドで実装する必要があることに注意してください。

116
Bozho

はい、そうすべきです!

デフォルトのJava.lang.ObjectequalsおよびhashCode実装をオーバーライドしない場合:

@Entity(name = "Book")
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    //Getters and setters omitted for brevity
}

merge操作は異なるオブジェクトインスタンスを返し、等式コントラクトは壊れます この投稿で説明するように

最善の方法は、次のようにビジネスキーを使用することです。

@Entity
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @NaturalId
    private String isbn;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(getIsbn(), book.getIsbn());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getIsbn());
    }

    //Getters and setters omitted for brevity
}

識別子を平等に使用することもできますが、hashCodeの実装は、すでに説明した同じ投稿で説明されているように、常に同じ値を返す必要があることに注意してください。

@Entity
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(getId(), book.getId());
    }

    @Override
    public int hashCode() {
        return 31;
    }

    //Getters and setters omitted for brevity
}
15
Vlad Mihalcea

はい、対応するequals()およびhashcode()メソッドを定義する必要がありますが、idをいずれかの一部にしないでください。 (同様の質問の 私の最近の回答 を参照)

13
7
Cid54

IDE generate hashCode()およびequals()を生成する傾向があります。ただし、注意してください。JPAエンティティ用のこれらのメソッドを生成するとき。equals()クラスアイデンティティのチェック

// ... inside equals() - wrong approach for Entities (cause of generate proxies)
if (o == null || this.getClass() != o.getClass()) {
        return false;
}
// ...

これらのライブラリは、たとえばHibernateのMyGreatEntity_$$_javassist_7のように、エンティティ(サブクラス)のプロキシを作成するため、一部のJPAライブラリを使用するとコレクションが破損します。

エンティティでは、equals()のサブクラスを常に許可します。

5
zbig

それが唯一の方法です。 Pojomatic ライブラリを試してみるとよいでしょう。

2
Boris Pavlović