java - 使い方 - spring jpa delete




JPA(および対応する結合表の行)でManyToMany関係を持つエンティティを削除する方法はありますか (5)

私は2つのエンティティ、GroupとUserを持っているとしましょう。 すべてのユーザーは多数のグループのメンバーになれ、各グループには多数のユーザーがいることができます。

@Entity
public class User {
    @ManyToMany
    Set<Group> groups;
    //...
}

@Entity
public class Group {
    @ManyToMany(mappedBy="groups")
    Set<User> users;
    //...
}

今はグループを削除したいと思います(メンバーが多いとしましょう)。

いくつかのグループでEntityManager.remove()を呼び出すと、JPAプロバイダ(私の場合はHibernate内) 外部テーブルの制約のためにジョインテーブルから行を削除せず 、削除操作が失敗するという問題があります。 ユーザーのremove()を呼び出すとうまくいきます(これは関係の所有側と関係していると思います)。

では、この場合にどのようにグループを削除できますか?

私が考え出すことができるのは、グループ内のすべてのユーザーをロードし、すべてのユーザーが自分のグループから現在のグループを削除し、ユーザーを更新することです。 しかし、このグループを削除できるように、グループのすべてのユーザーに対してupdate()を呼び出すのはばかげているようです。


JPA / Hibernateの代わりに、(Oracle構文)のように、結合表のforeginキーのデータベース定義にCASCADE DELETE句を使用できます。

CONSTRAINT fk_to_group
     FOREIGN KEY (group_id)
     REFERENCES group (id)
     ON DELETE CASCADE

こうすることで、DBMS自体が、グループを削除するときに自動的にグループを指す行が削除されます。 そして、削除がHibernate / JPA、JDBCから行われたかどうかは、手動でDBで行うか、それとも他の方法で行ってもかまいません。

カスケード削除機能は、すべての主要なDBMS(Oracle、MySQL、SQL Server、PostgreSQL)でサポートされています。


これは私のために働く:

@Transactional
public void remove(Integer groupId) {
    Group group = groupRepository.findOne(groupId);
    group.getUsers().removeAll(group.getUsers());

    // Other business logic

    groupRepository.delete(group);
}

また、メソッド@Transactional(org.springframework.transaction.annotation.Transactional)をマークすると、これは1つのセッションで全プロセスを実行し、時間を節約します。


その価値については、私はEclipseLink 2.3.2.v20111125-r10461を使用しています。@ManyToMany単方向関係がある場合、私はあなたが記述した問題を観察します。 しかし、双方向の@ManyToMany関係に変更すると、所有していない側からエンティティを削除することができ、JOINテーブルが適切に更新されます。 これは、カスケード属性を使用しない場合のすべてです。


以下は私のために働く。 関係(Group)の所有者ではないエンティティに次のメソッドを追加します。

@PreRemove
private void removeGroupsFromUsers() {
    for (User u : users) {
        u.getGroups().remove(this);
    }
}

これが機能するためには、グループには更新されたユーザーリストが必要です(自動的には行われません)。 ユーザーエンティティのグループリストにグループを追加するたびに、グループエンティティのユーザーリストにもユーザーを追加する必要があります。


  • 関係の所有権は、 'mappedBy'属性をアノテーションに配置する場所によって決まります。 あなたが 'mappedBy'を置くエンティティは、所有者ではないエンティティです。 両者がオーナーになる機会はありません。 「ユーザーの削除」ユースケースがない場合、現在はUserが所有者であるため、所有権をGroupエンティティに移動することができます。
  • 一方で、あなたはそれについて尋ねていませんが、知る価値のあるものはあります。 groupsusersは互いに結合されていません。 つまり、User1インスタンスをGroup1.usersから削除した後、User1.groupsコレクションは自動的に変更されません(これは私にとっては驚くべきことです)。
  • すべてでは、誰が所有者であるかを決めることをお勧めします。 Userが所有者であるとしましょう。 ユーザーを削除すると、関係ユーザーグループが自動的に更新されます。 しかし、グループを削除するときは、次のように関係を自分自身で削除する必要があります。
entityManager.remove(group)
for (User user : group.users) {
     user.groups.remove(group);
}
...
// then merge() and flush()




orm