57151


JPAのエンティティクラスに、`equals`メソッドや`hashCode`メソッドは明示的に実装する必要がありますか？  
またその場合、主キーのみに基いて比較判定する処理であれば良いですか？

それとも、`@Id`アノテーションがついているだけで良いですか？  
（JPAの内部で`@Id`付きフィールドを探して比較してくれる？）

`@Embeddable`を付けた複合主キークラスは、`equals`と`hashCode`を実装しなければならない、ということは、以下サイトで知りましたが・・・  
<http://enterprisegeeks.hatenablog.com/entry/2015/04/27/134840>

関連しそうな情報を見つけましたが、英語が苦手なせいか、よく分かりませんでした：  
<https://stackoverflow.com/questions/4388360/should-i-write-equals-methods-in-
jpa-entities>  
<https://developer.jboss.org/wiki/EqualsandHashCode>


CC BY-SA 3.0
2017-01-25T09:21:34.383
32149
2019-08-04T04:33:26.673
2017-05-23T12:38:56.467
-1
8078
question
java jpa
JPAのエンティティにはequalsとhashCodeを実装すべきか？


まず、`equals`と`hashCode`のオーバーライドが重要になってくるのは、主にオブジェクトを`Set`や`Map`といったコレクションに入れる場合です。  
コレクションの内部処理が`equals`と`hashCode`に依存しているためです。  
なので、エンティティオブジェクトをコレクションに入れたり、比較したりする必要がないのなら、`equals`と`hashCode`のオーバーライドが必要というわけではないでしょう。

> （JPAの内部で@Id付きフィールドを探して比較してくれる？）

このようなことはしてくれないと思います。  
[APIリファレンス](http://docs.oracle.com/javaee/6/api/javax/persistence/Id.html)にもそんなことは書いてありませんし。

[この記事](https://developer.jboss.org/wiki/EqualsandHashCode)を読むと以下の様な見解になります。  
エンティティクラスでは`equals`と`hashCode`をオーバーライドするのがベストプラクティスです。  
ひとつのセッションの中でセッションにアタッチされたエンティティオブジェクトだけを扱うのであれば、JPAプロバイダがインスタンス管理をしてくれるので`Object#equals`そのままでも問題なく扱えますが、普通はそうはいきません。  
複数のセッションにまたがってエンティティオブジェクトを扱う場合、JPAプロバイダはインスタンスを管理しきれないので、同じレコードを表すオブジェクトが異なるインスタンスになります。  
この場合、`equals`をオーバーライドしないと適切な比較ができません。  
また、`equals`で比較するのは、JPAプロバイダが自動生成するIDよりも、アプリ側でセットするユニークなフィールド(自然キーがベスト)がいいようです。  
これは単にIDの自動生成前でも`equals`を使えるようにするためです。  
その必要がなければ自動生成するIDを比較するだけでよさそうですが。


CC BY-SA 3.0
2017-03-04T08:08:11.770
33087
2017-03-04T08:08:11.770
19437
32149
answer


(既に正しいと私が考える回答は出ていますが、別の説明を試みてみます)

* * *

一般的なクラス設計の話として、[Effective Java 第3版](https://www.maruzen-
publishing.co.jp/item/?book_no=303054) 第3章 項目10 "`equals`
をオーバーライドするときは一般契約に従う" に次のように書かれています:

> `equals`
> メソッドをオーバーライドするのは簡単なように思えますが、間違ったやり方でオーバーライドしてしまう方法はたくさんあり、その結果は悲惨なものになります。問題を避ける最も簡単な方法は、`equals`メソッドをオーバーライドしないことです。  
>  (中略)  
>  では、いつ `equals` をオーバーライドするのが適切でしょうか。それは、クラスが単なるオブジェクトの同一性とは異なる論理的等価性(logical
> equality)という概念を持っていて、かつスーパークラスが`equals`をオーバーライドしていないときです。

JPAエンティティクラスはどうかというと、論理的等価性はあります(簡単にいうと`@Id`フィールドの値が同じであれば論理的に等価です(※十分条件であって必要条件ではない))。  
ただし、JPAフレームワークは、論理的に等価であればデフォルト実装の`equals`も`true`になるよう(可能な限り)取り計らってくれますので、デフォルト実装で大抵の場合うまく動きます。

* * *

質問文に書かれているリンクより新しく具体的な説明がHibernateのユーザガイドにあります。

  * [2.5.7. Implementing equals() and hashCode()](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode) \- Hibernate ORM 5.4.4.Final User Guide

> Generally, this is pertinent for user-defined classes used as composite
> identifiers. Beyond this one very specific use case and few others we will
> discuss below, you may want to consider not implementing equals/hashCode
> altogether.

* * *

質問文に対するそれぞれの回答としては:

> JPAのエンティティクラスに、equalsメソッドやhashCodeメソッドは明示的に実装する必要がありますか？

通常は不要です。(原理主義的には実装するのが正しいですが、それより誤った実装を行ってしまうリスクを懸念すべきです。)

> またその場合、主キーのみに基いて比較判定する処理であれば良いですか？

(これは`equals`のオーバーライドが難しいことの1つの具体例ですが)  
一般的にはこの考えは誤っています。  
例えば `@Id` を `@GeneratedValue` で決定するJPAエンティティクラスは、永続化するまで主キーがありません。

> それとも、@Idアノテーションがついているだけで良いですか？  
>  （JPAの内部で@Id付きフィールドを探して比較してくれる？）

通常はその考えで良いです。  
(同一Persistence Contextでは)同一`@Id`は同一インスタンスとなるよう取り計らってくれるので、`@Id`が同じなら `==`
が`true`であり、すなわち`equals`が`true`になります。


CC BY-SA 4.0
2019-08-04T04:33:26.673
57151
2019-08-04T04:33:26.673
2808
32149
answer