3

私は#hibernateIRCにいて、誰かが次の(部分的な)パターンを私と共有しました

@Entity
public MyEntity() {

  ... primary key, object properties, getters/setters go here ...    

  @Column(nullable=false)
  private int hashCode;

  public MyEntity() {
     hashCode += id;
  }

  private final Set<String> tags = Sets.newHashSet();

  public void addTag(String tag) {
     if(tags.add(tag)) {
         hashCode += tag.hashCode();
     }
  }

  public void removeTag(String tag) {
     if(tags.remove(tag) {
        hashCode -= tag.hashCode();
     }
  }

  public void hashCode() {
    return hashCode;
  }

  ... http://www.artima.com/lejava/articles/equality.html style equals ...
}

これを「断片的に更新されるキャッシュされた hashCode」と呼ぶことができます。(一部のコメンターが信じているように、これは間違いなく「ビジネス キー」パターンではありません。「ビジネス キー」パターンには、等価性テストに使用されるユーザー名のように、一意性制約を持つ列が必要です)。

JPA/Hibernate で使用すると、 JBoss Equals and HashCode 記事@Entityの「ビジネス [sic] キーを使用した eq/hC」と同様の利点があり、開発者が通常の Javabean オブジェクトの動作を期待する方法で動作することを意味します (つまり、データベース行のようなオブジェクトについて考える必要はありません): DB に永続化される前。取得モードの後。およびモード内またはモードでいつでもフェッチできます。TransactionEAGERLAZYTransactionEXTENDED

ただし、hashCodeが常に正しく更新されていることを確認することは、実際の課題になる可能性があります。

このパターンを経験したことがある人はいますか? それについての発見 (ポジティブとネガティブの両方) を共有できますか? 私は Gotchas に非常に興味がありますが、なぜそれが悪いのかについて確固たる議論なしに何かが「悪い」と主張するコメントにはまったく興味がありません.

私はJPA hashCode() / equals() ジレンマを認識していますが、このパターンが実際にその議論でカバーされているとは思わないことに注意してください。

このパターンは当初、EAGER @ElementCollection を使用した find() での Hibernate LazyInitializationException で発生するような、ネストされたCollections をs にロードする際の問題を回避する方法として提案されました。@Entity

更新: 一部のコメンターは、既存のアプローチに非常に熱心になっています。誤解を避けるために、私はこの新しいパターンのメリットにのみ興味があります。ご参考までに、また、equals/hashCode をどのように実装する必要があると考えているかを言うのをやめていただくようお願いするために、私@Entityは数年間、私の s に次のパターンを使用してきたことに注意してください。

@Id
private UUID id = UUID.randomUUID();

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (!(obj instanceof MY_CLASS) || id == null)
        return false;
    MY_CLASS other = (MY_CLASS) obj;
    return id.equals(other.id);
}

@Override
public int hashCode() {
    Preconditions.checkNotNull(id, "id must be set before @Entity.hashCode can be called");
    return id.hashCode();
}

そして、私は最近、このような別の方法が本当に必要かどうかを確認するために何か新しいことを試みました

public boolean hasSameProperties(Note other) {
    Preconditions.checkNotNull(other);
    if (this == other)
        return true;
    return Objects.equal(source, other.source)
            && Objects.equal(title, other.title)
            && Objects.equal(tags, other.tags)
            && Objects.equal(contents, other.contents);
}
4

2 に答える 2

1

このビジネス キーは一意ではないため、equals() の選択としては適切ではないようです。

ビジネス キー 1002 にはタグ 500 とタグ -502 が追加され、ビジネス キー 995 にはタグ 3 とタグ 2 が追加されますか? それらのオブジェクトは本当に等しいことを意味していますか?

32 ビット数の衝突のリスクが比較的低いことは、特定のエンティティが提供する目的に関係なく許容できる場合がありますが、何かを「パターン」として参照するには、特定のエンティティに対して恣意的に失敗する可能性が低いだけでなく、実際に正しいことを望みます。データサイズ。

于 2012-07-30T22:23:55.603 に答える
0

これが悪い考えである理由を説明する2、3の長い答えを書き、書き直し、削除しましたが、最終的には、それらはすべてオブジェクトIDとは何かの基本的な説明であり、あなたはそれを理解していると確信しています。

このパターンに対する私の反応は、解決する必要のある問題を解決しないということです。

主張されている「hashCode/equals問題」の解決策は非常に簡単です。エンティティを作成するときに、エンティティに識別子を付けます。それを永続化します。ベースequalshashCodeそれに基づいて。挿入時にデータベースまたは永続層によって作成された識別子に依存しないでください。これは今では前向きに古代の原則です。

余談ですが、エンティティの場合、どちらかまたは可変フィールドに基づくことは決して正しくありません。それは、エンティティの平等がどのように機能するかではありません。エンティティは単なる国家の袋ではなく、ある国家がたまたま付けられたアイデンティティです。平等とハッシュコードは、状態ではなくIDに基づいている必要があります。equalshashCode

于 2012-07-31T08:05:03.817 に答える