1. 概要

このチュートリアルでは、JPAエンティティオブジェクトとの同等性の処理について見ていきます。

2. 考慮事項

一般に、平等とは、単に2つのオブジェクトが同じであることを意味します。 ただし、Javaでは、 Object.equals()メソッドとObject.hashCode()メソッドをオーバーライドすることで、等式の定義を変更できます。 最終的に、Javaを使用すると、等しいとはどういう意味かを定義できます。しかし、最初に、考慮しなければならないことがいくつかあります。

2.1. コレクション

Javaコレクションは、オブジェクトをグループ化します。 グループ化ロジックは、ハッシュコードと呼ばれる特別な値を使用して、オブジェクトのグループを決定します。

hashCode()メソッドによって返される値がすべてのエンティティで同じである場合、これにより望ましくない動作が発生する可能性があります。 エンティティオブジェクトにidとして定義された主キーがあるが、 hashCode()メソッドを次のように定義するとします。

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

コレクションはすべて同じハッシュコードを共有するため、それらを比較するときに異なるオブジェクトを区別することはできません。 幸い、これを解決するのは、ハッシュコードを生成するときに一意のキーを使用するのと同じくらい簡単です。 たとえば、 id を使用して、 hashCode()メソッドを定義できます。

@Override
public int hashCode() {
    return id * 12345;
}

この場合、エンティティのidを使用してハッシュコードを定義しました。 これで、コレクションでエンティティを比較、並べ替え、保存できるようになりました。

2.2. 一時的なエンティティ

永続コンテキストとの関連付けがない新しく作成されたJPAエンティティオブジェクトは、一時的な状態にあると見なされます。 これらのオブジェクトには通常、@Idメンバーが設定されていません。 したがって、 equals()または hashCode()が計算に id を使用する場合、これは、 id [ X165X]はすべてnullになります。 これが望ましい場合は多くありません。

2.3. サブクラス

平等を定義する場合、サブクラスも問題になります。 equals()メソッドでクラスを比較するのが一般的です。 したがって、 getClass()メソッドを含めると、オブジェクトが等しいかどうかを比較するときにサブクラスを除外するのに役立ちます。

オブジェクトが同じクラスであり、同じ idを持つ場合にのみ機能するequals()メソッドを定義しましょう。

@Override
public boolean equals(Object o) {
    if (o == null || this.getClass() != o.getClass()) {
        return false;
    }
    return o.id.equals(this.id);
}

3. 平等の定義

これらの考慮事項を考慮すると、平等を処理する際にいくつかの選択肢があります。 したがって、私たちが採用するアプローチは、オブジェクトの使用方法の詳細によって異なります。 オプションを見てみましょう。

3.1. オーバーライドなし

デフォルトでは、Javaは、 Object クラスの子孫であるすべてのオブジェクトにより、 equals()および hashCode()メソッドを提供します。 したがって、私たちができる最も簡単なことは何もありません。 残念ながら、これは、オブジェクトを比較するときに、等しいと見なされるためには、同じオブジェクトを表す2つの別個のインスタンスではなく、同じインスタンスである必要があることを意味します。

3.2. データベースキーの使用

ほとんどの場合、データベースに格納されているJPAエンティティを処理しています。 通常、これらのエンティティには、一意の値である主キーがあります。 したがって、同じ主キー値を持つこのエンティティのインスタンスはすべて等しくなります。 したがって、オーバーライドできます equals() 上記のサブクラスで行ったように、またオーバーライドしますハッシュコード() 両方で主キーのみを使用します。

3.3. ビジネスキーの使用

または、ビジネスキーを使用してJPAエンティティを比較することもできます。 この場合、オブジェクトのキーは、主キー以外のエンティティのメンバーで構成されます。 このキーにより、JPAエンティティが一意になります。 ビジネスキーを使用すると、プライマリキーまたはデータベースで生成されたキーを必要とせずにエンティティを比較するときに同じ望ましい結果が得られます。

@Id フィールドでなくても、電子メールアドレスは常に一意であることがわかっているとします。 hashCode()および equals()メソッドに電子メールフィールドを含めることができます。

public class EqualByBusinessKey {

    private String email;

    @Override
    public int hashCode() {
        return java.util.Objects.hashCode(email);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (obj instanceof EqualByBusinessKey) {
            if (((EqualByBusinessKey) obj).getEmail().equals(getEmail())) {
                return true;
            }
        }

        return false;
    }
}

4. 結論

このチュートリアルでは、JPAエンティティオブジェクトを作成するときに同等性を処理できるさまざまな方法について説明しました。 また、アプローチを選択する際に考慮すべき考慮事項についても説明しました。 いつものように、完全なソースコードはGitHubにあります。