15

ID とバージョンのプロパティを抽象化する BaseEntity が 1 つあります。このクラスは、PK (id) プロパティに基づいて hashcode と equals も実装します。

BaseEntity{

    Long id;
    Long version; 

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    BaseEntity other = (BaseEntity) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}


}

現在、2 つのエンティティ A と B は、以下のように BaseEntity を拡張しています。

A extends BaseEntity{
    `B b`
     B getB(){return b;)
     void setB(B b){this.b=b;}
}

B extends BaseEntity{
}

object b1;
object a1;
a1.set(b1);
session.save(a1) //cascade save;

セッションを閉じて a を lazy b でロードし、a1.getB().equals(b1) を試してみると false になりますが、a1.getB().getId().equals(b1.getId()) と比較すると true が返されます。とにかくこれを解決するには、Javaアシストプロキシオブジェクトが原因だと思いますか?

4

4 に答える 4

37

アソシエーションを遅延ロードできるようにするためにa.b、Hibernateはbフィールドをaプロキシに設定します。プロキシはBを拡張するクラスのインスタンスですが、Bではありません。したがって、非プロキシBインスタンスをプロキシBインスタンスと比較する場合、equals()メソッドは常に失敗します。これは、両方のオブジェクトのクラスを比較するためです。

if (getClass() != obj.getClass())
    return false;

Hibernateエンティティの場合、これを次のように置き換える必要があります

if (!(obj instanceof B)) {
    return false;
}

また、注意してください

  • Hibernateは、IDを実装equals()hashCode()て使用するのではなく、自然な識別子を使用することをお勧めします。IDを使用して実装すると、保存されてIDが生成されるまでエンティティにIDがないため、問題が発生する可能性があります。
  • エンティティの継承を使用する場合、問題はさらに悪化します。Bが2つのサブエンティティB1とB2のスーパークラスであると仮定します。Hiberanteはa.b、ロードする前にどちらのタイプ(B1またはB2)であるかを知ることができません。したがってa.b、Bのサブクラスであるが、B1またはB2のサブクラスではないプロキシに初期化されます。したがって、メソッドhashCode()equals()メソッドはBで実装する必要がありますが、B1とB2でオーバーライドしないでください。2つのBインスタンスがBのインスタンスであり、同じ識別子を持っている場合は、等しいと見なす必要があります。
于 2012-07-02T19:13:46.660 に答える
3

このように動作させることもできます。これは、インスタンスが B であるかわからない場合に役立ちます (equalsスーパークラスにある場合に発生する可能性があります) 。

if (HibernateProxyHelper.getClassWithoutInitializingProxy(this) != HibernateProxyHelper.getClassWithoutInitializingProxy(obj)) 
    return false
于 2014-04-10T09:50:06.260 に答える
-1

これは主に、標準のJava継承の影響です。

a1.getB().equals(b1)(クラスでequals()をオーバーライドした場合を除いて)を使用Object.equals()します。これは、a1.getB()とb1が同じインスタンスである場合にのみtrueを返します。正確に何をしたかはわかりませんが(コードのフォーマットが壊れています)、a別のセッションで再度ロードしたように見えるため、との新しいインスタンスを取得し、a結果a.getB()としてObject.equals()falseを返します。

a1.getB().getId().equals(b1.getId())を使用しますLong.equals()。これは、long値が同じである場合(Longオブジェクトのインスタンスが異なる場合でも)、これらの値が明らかに同じである場合にtrueを返します。

于 2012-06-13T11:45:10.383 に答える