1

とマークされた(同じエンティティ上の)Entity双方向の関係を持つがあります。ManyToManyCascadeType.ALL

Contactエンティティの検索方法は次のとおりです。

@ManyToMany(cascade= CascadeType.ALL)
private List<Contact> parentContacts = new ArrayList<Contact>();
@ManyToMany(cascade= CascadeType.ALL, mappedBy="parentContacts")
private List<Contact> childContacts = new ArrayList<Contact>();

このエンティティを保存することになっているサーバー側のメソッドがあります。

public AltContact saveContact(EntityManager em, Contact contact, List<Contact> childs) {
    for (Contact c : childs) {
        contact.getChildContacts().add(c);
        c.getParentContacts().add(contact);
    }
    if (contact.getId() == null) {
        em.persist(contact);
    } else {
        contact = em.merge(contact);
    }
    return contact;
}

contactリストのまたはエンティティがchilds永続化されていない場合は、うまく機能します。ただし、すでに永続化されているエンティティでメソッドを使用する必要がある場合がありsaveContactます。これを実行しようとすると、JPAが関係のすべてのエンティティを永続化しようとし、例外が発生するようです。

Internal Exception: java.sql.SQLIntegrityConstraintViolationException

確かに、それは永続化してすでに永続化されているエンティティを試行するため、のIDフィールドの単一性Contactに違反します。

これをどのようにアクティブにできますか?私のアプローチの何が問題になっていますか?

Eclipselink / JPAが、関係の一部であり、すでに永続化されているエンティティを永続化しようとしないようにするにはどうすればよいですか?

4

1 に答える 1

2

親の連絡先エンティティが新しいが、一部の子が存在する(ただし切り離されている)場合は、親でpersistを呼び出さないでください。これにより、persistが子にカスケードされ、例外がスローされるようになります。すぐに、またはフラッシュ/コミット時に。新しい親の連絡先でperistに電話をかけたい場合は、既存の子を見つけて、管理対象インスタンスを新しい連絡先に関連付けるようにしてください。存在しない場合は、子を個別に永続化するか、永続化が関係をカスケードして自動的に実行できるようにすることができます。

ただし、一般的には、新しい親の連絡先でmergeを呼び出して、それが更新か挿入かをプロバイダーに判断させる方がはるかに簡単です。マージは子にカスケードされるため、子も必要に応じて挿入または更新されます。

ただし、カスケードの使用には注意してください。親を削除しようとすると、削除も子にカスケードされ、子は親コレクション内のすべての親にカスケードされます。正しく管理されていないと、意図せずにすべての連絡先が削除される可能性があります。また、子がリストから削除される原因となる変更は、正しくカスケードされない場合があることにも注意してください。カスケードマージは、現在コレクションにあるエンティティに対してのみ機能し、以前は存在していたエンティティに対しては機能しません。そのため、親のコレクションから子を削除するときに手動で子のマージを呼び出すか、別のパスを介して子がマージされていることを確認する必要があります。

于 2012-11-22T15:39:15.813 に答える