1

エンティティ オブジェクトが 2 つの列に制約のあるテーブルにマップされている MySQL データベースに接続された JPA プロジェクトがあります。あれは:

@Entity
@Table(name = "my_entity")
class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "myField1")
    private String myField1;
    @Basic(optional = false)
    @Column(name = "myField2")
    private int myField2;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "myEntity")
    private Set<OtherEntity> otherEntitySet;
}

データベースでは、my_entity テーブルに (myField1, myField2) に対する一意の制約があります。問題は、EntityManager.remove(entity) で既存のエンティティを削除してから、EntityManager.persist(entity) で新しいエンティティを追加すると、データベースが重複行に関するエラーをスローすることです。

例えば:

entityManager.getTransaction().begin();

MyEntity entity1 = new MyEntity();
entity1.setMyField1("Foo");
entity1.setMyField2(500);
entityManager.persist(entity1);

entityManager.getTransaction().commit();
entityManager.getTransaction().begin();

entityManager.remove(entity1);

MyEntity entity2 = new MyEntity();
entity2.setMyField1("Foo");
entity2.setMyField2(500); 
entityManager.persist(entity2);

entityManager.getTransaction().commit();

これにより、MySQLIntegrityConstraintViolationException が発生し、これが重複したエントリであると不平を言います。古いエントリを削除する前に新しいエントリを追加しようとしているからだと思います。その秩序を維持する方法はありますか?または、この状況を防ぐために JPA を使用する方法はありますか? これは一般的な使用例ではありませんが、エンティティを削除して関連するすべてのデータを削除して最初からやり直そうとし、簡単なフィールドを再作成してから、データが削除されていないことに気付くユーザーについて心配しています。

hashCode と equals の実装は次のとおりです。

public int hashCode() {
    int hash = 0;
    hash += (getMyField1().hashCode() + getMyField2());
    return hash;
}

public boolean equals(Object object) {
    if (!(object instanceof MyEntity)) {
        return false;
    }
    MyEntity other = (MyEntity) other;
    return (getMyField2() == other.getMyField2()) &&
        (getMyField1().equals(other.getMyField1()));
}
4

2 に答える 2

2

JPA で操作順序を指定する標準的な方法はないと思います。そのため、ステートメントが実行される順序は保証されません。理想的には、JPA 実装は、この状況を検出して挿入前に削除を実行するのに十分なほど賢いですが、それは頻繁に失敗する領域です。または、データベースが遅延制約チェックをサポートしている場合 (たとえば、Oracle はサポートしていますが、MySQL はサポートしていません) )、データベースはコミット時間まで待機して一意制約違反の例外を与えることでこれを処理します。

したがって、1 つの解決策は、remove(entity1) への呼び出しの後に追加のコミットを実行することです。別の可能性は、entity2 を作成する前に、データベースに存在するかどうかを最初に確認し、存在する場合はそれを使用することです。これらのオプションはどちらもやや面倒で、すべてのワークフローに適しているわけではありません。現在の JPA 実装のドキュメントを調べて、役立つ拡張機能が提供されているかどうかを確認してください。

于 2009-12-19T15:43:35.303 に答える