为什么合并不是一对多关系的级联

时间:2012-10-31 07:33:49

标签: java jpa eclipselink ejb-3.1

我的问题与我的其他问题Explicit delete on JPA relationships几乎相似 但我想进一步简化它以保证更详细的答案。

想象一下,我和父母之间有一个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;
}

在我的界面中,我正在显示父级列表。用户可以选择一个父母,他/她可以编辑其子女列表。 为了说明这一点,我使用了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);
        }
    }
}

我的问题是,我可以更改父级的名称,但对子级列表的任何更改都不会反映到数据库中。 它不会改变或执行任何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;
}

2 个答案:

答案 0 :(得分:7)

这是合并的标准问题。将收集对集合中子对象的更改。

合并调用只能级联列表中的对象,因此对列表中不存在的对象的更改会丢失。不幸的是,oneToMany并不拥有这种关系:孩子的ManyToOne就是这样。因此,需要合并子实体以使更改被显示并推送到数据库。子实体是独立的对象,需要在更改时单独合并。那,或者添加到不同的父/树中以进行合并。

答案 1 :(得分:1)

您的问题What could be the cause?。原因是parentNew的价值内容。如果parentNew是以下原因之一,则不会影响/更新为子。

  1. 没有参考实例父母和孩子的老虎钳签证。 ---&GT; 会抛出异常。
  2. Parent参数值包含Clild的空列表或空列表 - &gt; 这将是您的理由。
  3. Child没有从UI获取更新名称.--&gt; 这将是您的理由。
  4. 实施例。我快写了。没关系。

    DB中已存在数据

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

    Upldated:

    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);