17

ここでの私の質問は、他の質問JPA 関係の明示的な削除とほとんど似ていますが 、より詳細な回答を保証するために、さらに単純化することを考えました。

親と子の間に OneToMany 関係があるとします。

@Entity
public class Parent {
    private String name;
    @OneToMany(mappedBy="owner",cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private List<Child> children;
}
@Entity
public class Child {
    private String name;
    @ManyToOne
    private Parent owner;
}

私の UI では、親のリストを表示しています。ユーザーは 1 つの親を選択でき、その子のリストを編集できます。これを示すために、 currentParent 変数を使用して、現在編集されている親を表しています。ユーザーは、子供の名前を追加/編集することを選択できます。

ボタンをクリックすると、EJB 呼び出しを使用して新しい子のリストを保存します。

@ViewScoped
public class MyBean(){
    private Parent currentParent;
    @EJB
    private MyEJB myEJB;

    public void saveChanges(){
        myEJB.save(currentParent);
    }
}

私の EJB 呼び出しは次のようになります。

@Stateless
public class MyEJB{
    @PersistenceContext(unitName = "MyPU")
    private EntityManager em;

    public void save(Parent parentNew){
        Parent pOld = em.find(entityClass,  p.getId());
        if(pOld !=null){
            pOld.setName(parentNew.getName());
            pOld.setChildren(parentNew.getChildren());
            em.merge(pOld);
        }
    }
}

私の問題は、親の名前を変更することはできますが、子リストへの変更は DB に反映されないことです。子を削除/更新/追加するために SQL を変更または実行することはありません。

原因は何ですか?

アップデート

いくつかの試行錯誤とさまざまなリンクを読んだ後、 @onetomany で orphanRemoval オプションを設定すると問題が解決するようです。Eclipselink は、マージ中に孤立した行を自動的に削除します。

JPAの複雑さはこれで終わりです..

@Entity
public class Parent {
    private String name;
    @OneToMany(mappedBy="owner",cascade=CascadeType.ALL, fetch=FetchType.EAGER,orphanRemoval = true)
    private List<Child> children;
}
4

2 に答える 2

8

これはマージの標準的な問題です。コレクション内の子オブジェクトへの変更が取得されます。

マージ呼び出しは、リストにあるオブジェクトに対してのみカスケードできるため、リストにないオブジェクトへの変更は失われます。残念ながら、oneToMany は関係を所有していません。子の ManyToOne が所有しています。そのため、変更を表示してデータベースにプッシュするには、子エンティティをマージする必要があります。子エンティティは独立したオブジェクトであり、変更されたときに個別にマージする必要があります。それ、または別の親/ツリーに追加してマージします。

于 2012-10-31T12:37:18.257 に答える
1

あなたの質問What could be the cause?。の値内容が原因ですparentNew。以下のいずれかの原因の場合、parentNew子への影響/更新は行われません。

  1. 参照インスタンスの親子万力ビザはありません。--->例外がスローされます。
  2. Parentパラメータ値にnullまたは空のリストがありますClild->これが原因です。
  3. ChildUI から更新された名前を取得しないでください。--> これが原因です。

例。取り急ぎ書きます。大丈夫です。

DBにすでにデータが存在する

Parent                      Child
==================    =======================================
'P001', 'Parent 1'   'C002', 'Child 2', 'P001'
                     'C003', 'Child 3', 'P001'
                     'C001', 'Child 1', 'P001'

更新後:

Parent                      Child
==================          =======================================
'P001', 'Update Parent 1'   'C002', 'Update Child 2', 'P001'
                            'C003', 'Update Child 3', 'P001'
                            'C001', 'Update Child 1', 'P001'

List<Child> clidList = new ArrayList<Child>();
Parent parent = new Parent("P001", "Update Parent 1", clidList);
Child c1 = new Child("C001", "Update Child 1", parent);
Child c2 = new Child("C002", "Update Child 2", parent);
Child c3 = new Child("C003", "Update Child 3", parent);
clidList.add(c1);
clidList.add(c2);
clidList.add(c3);

Parent existingParent = em.find(Parent.class, parent.getId());
existingParent.setName(parent.getName());
existingParent.setChildren(parent.getChildren());
em.merge(existingParent);
于 2012-10-31T09:44:52.547 に答える