4

私の特定の使用パターンを考えると、このアプローチの何が問題なのかを理解しようとしています:

@Entity
public class DomainObject {
  @Id // + sequence generator
  private Long id;

  @Override
  public boolean equals(Object o) {
    // bunch of other checks omitted for clarity
    if (id != null) { 
      return id.equals(o.getId());
     }
     return super.equals(o);
  }

  @Override
  public int hashCode() { 
    if (id != null) {
      return id.hashCode();
    } 
    return super.hashCode();
}

この件に関するいくつかの投稿を読みましたが、DB で生成されたシーケンス値を equals/hashCode で使用したくないようです。オブジェクトが永続化されるまで設定されず、異種の一時的な値が必要ないためです。そうしないと、永続層自体が壊れる可能性があります。

しかし、一時的なオブジェクトのデフォルトの Object equals/hashCode (インスタンスの等価性) にフォールバックし、生成された @Id を使用することに何か問題がありますか?

私が考えることができる最悪のことは、一時的なオブジェクトが永続的なオブジェクトと等しくなることは決してないということです.これは私のユースケースでは問題ありませんcontains.すでに永続的で、すべて ID を持っています。

ただし、永続化レイヤーの奥深くで、非常に微妙で明白ではない方法で何か他の問題があるように感じますが、何が原因かはわかりません。

他のオプションもそれほど魅力的ではないようです。

  • 何もせず、インスタンスの等価性 (デフォルトの Object.equals) で生活する: 私のエンティティのほとんどでうまく機能しますが、切り離されたエンティティ (セッション スコープなど) が混在するコレクションが必要な場合のいくつかのケースの回避策にうんざりしています。現在のトランザクションからの「ライブ」のもの

  • ビジネス キーの使用: 明確な自然キーがありますが、それらは可変であり、これには上記と同じ問題がいくつかあります (オブジェクトが変更された場合の hashCode の安定性)

  • UUID を使用する - それが機能することはわかっていますが、Java.util コレクションをサポートするために DB をアーティファクトで汚染するのは間違っていると感じています。

以下も参照してください。

4

3 に答える 3

2

Mapのjavadoc には次のように書かれています。

注: 変更可能なオブジェクトをマップ キーとして使用する場合は、細心の注意を払う必要があります。オブジェクトがマップ内のキーであるときに、等値比較に影響を与える方法でオブジェクトの値が変更された場合、マップの動作は指定されません。

オブジェクトが永続化されるたびに、実装によって equals の意味が変わります。そのため、そのオブジェクトを含むコレクションは、もはや正しく機能する必要はありません。特に、HashMap でキーとして使用される (または HashSet に含まれる) オブジェクトのハッシュコードを変更すると、その Map (Set) での将来のルックアップでオブジェクトが見つからず、そのオブジェクトが再度 Map (Set) に追加される可能性があります。通常の状況下では、Map には特定のキーごとに最大 1 つのマッピングが含まれ、Set にはすべてのオブジェクトが最大 1 回含まれますが、成功する可能性があります。

(ToMany アソシエーションを表現するために) エンティティをコレクションに格納することは一般的であるため、その欠陥は実際に見つけにくいバグを引き起こす可能性があります。

したがって、データベースで生成された識別子に基づくハッシュコードを実装しないことを強くお勧めします。

于 2012-11-13T20:51:49.900 に答える
0

はい、できます!ただし、この投稿で説明されているように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 getClass().hashCode();
    }
 
    //Getters and setters omitted for brevity
}

これは、equals と hashCode がすべてのエンティティ状態遷移で一貫していることを確認できる唯一の方法です。

于 2016-06-06T11:16:55.397 に答える