回答:
Hibernateはどのように上書きする際に/の素晴らしく、長い説明があるequals()
/ hashCode()
でドキュメントを
その要点は、エンティティがの一部であるSet
場合、またはインスタンスをデタッチ/アタッチする場合にのみ、心配する必要があるということです。後者はそれほど一般的ではありません。前者は通常、次の方法で処理するのが最適です。
equals()
/ hashCode()
ビジネスキーに基づく-たとえば、オブジェクト(または少なくともセッション)の有効期間中に変更されない属性の一意の組み合わせ。equals()
/ hashCode()
プライマリキー(設定されている場合)とオブジェクトID / System.identityHashCode()
以外の場合。ここで重要なのは、新しいエンティティを追加して永続化した後、セットをリロードする必要があることです。そうしないと、エンティティが現在のと一致しないバケットに割り当てられる可能性があるため、奇妙な動作が発生する可能性があります(最終的には、エラーやデータ破損が発生します)hashCode()
。refresh()
?Set
契約に従うエンティティはどのようにして間違ったバケットに入れられますか(十分なハッシュコード実装があると仮定して)。
Set.contains(entity)
そうすれば戻りfalse
ます。同じことがget()/ put()/などにも
受け入れられた答えは正確ではないと思います。
元の質問に答えるには:
ほとんどの場合、デフォルトの実装で十分ですか?
答えはイエスです、ほとんどの場合そうです。
あなただけオーバーライドする必要があるequals()
とhashcode()
実体がで使用される場合にはSet
(非常に一般的である)とエンティティからデタッチされ、その後に付け直し、(休止状態の珍しい用法である)セッションを休止します。
受け入れられた回答は、いずれかの条件が真の場合、メソッドをオーバーライドする必要があることを示しています。
最高equals
/ hashCode
あなたが使用している場合、実装は、独自のビジネスキーを。
ビジネスキーは、すべてのエンティティの状態遷移(一過性、接続、分離、削除)で一貫している必要があります。そのため、IDが等しいかどうかに依存できません。
別のオプションは、アプリケーションロジックによって割り当てられたUUID識別子の使用に切り替えることです。この方法では、エンティティーがフラッシュされる前にIDが割り当てられるため、equals
/にUUIDを使用できますhashCode
。
equals
およびのエンティティ識別子を使用することもできますが、エンティティのhashCode値がすべてのエンティティの状態遷移で一貫していることを確認するためにhashCode
、常に同じhashCode
値を返す必要があります。このトピックの詳細については、この投稿を確認してください。
BaseEntity
その問題について二度と考えないでください。db側には少しスペースが必要ですが、快適さのためにその価格を支払う方が良いでしょう:)
エンティティが遅延読み込みで読み込まれた場合、それは基本型のインスタンスではなく、javassistによって動的に生成されたサブタイプであるため、同じクラス型のチェックは失敗するため、使用しないでください。
if (getClass() != that.getClass()) return false;
代わりに:
if (!(otherObject instanceof Unit)) return false;
これは、Javaプラクティスでのequalsの実装で説明されているように、良いプラクティスでもあります。
同じ理由で、フィールドに直接アクセスすると、機能せず、基になる値の代わりにnullを返す場合があるため、プロパティで比較を使用せず、ゲッターを使用します。
ええ、それは難しいです。私のプロジェクトでは、equalsとhashCodeはどちらもオブジェクトのIDに依存しています。このソリューションの問題は、IDがデータベースによって生成されるため、オブジェクトがまだ永続化されていない場合はどちらも機能しないことです。私の場合、ほとんどすべての場合でオブジェクトはすぐに永続化されるので、それは許容できます。それ以外は、それは素晴らしい働きをし、実装が簡単です。
Hibernate 5.2のドキュメントには、状況によっては、hashCodeとequalsをまったく実装したくない場合があると記載されています。
一般に、同じセッションからロードされた2つのオブジェクトは、データベース内で等しい場合(hashCodeとequalsを実装せずに)等しくなります。
2つ以上のセッションを使用している場合は、複雑になります。この場合、2つのオブジェクトが等しいかどうかは、equalsメソッドの実装によって異なります。
さらに、equalsメソッドが、オブジェクトを初めて永続化するときにのみ生成されるIDを比較している場合は、問題が発生します。equalsが呼び出されたとき、まだ存在していない可能性があります。
ここにとても良い記事があります:https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html
記事の重要な行を引用すると:
ビジネスキーの等価性を使用して、equals()およびhashCode()を実装することをお勧めします。ビジネスキーの等価性とは、equals()メソッドがビジネスキーを形成するプロパティのみを比較することを意味します。これは、現実世界のインスタンスを識別するキー(自然な候補キー)です。
簡単な言葉で
public class Cat {
...
public boolean equals(Object other) {
//Basic test / class cast
return this.catId==other.catId;
}
public int hashCode() {
int result;
return 3*this.catId; //any primenumber
}
}
あなたがたまたまオーバーライドした場合はequals
、その契約を確実に満たしてください:-
オーバーライドhashCode
は、その契約がequals
実装に依存しているためです。
Joshua Bloch(コレクションフレームワークの設計者)は、これらのルールに従うよう強く求めました。
これらの契約に従わないと、重大な意図しない影響があります。たとえば、一般契約が履行されていないため、List#contains(Object o)
誤ったboolean
値が返される場合があります。