JPA Merge 和 Remove 不会同时级联到子对象
Posted
技术标签:
【中文标题】JPA Merge 和 Remove 不会同时级联到子对象【英文标题】:JPA Merge and Remove are not cascaded to child object at the same time 【发布时间】:2012-11-21 14:43:10 【问题描述】:我在商业项目中使用 Open JPA,并希望利用级联的 Parent->Child 删除和合并。
我模拟了一个显示问题的工作代码。
我有一个持久的 Parent 对象和一些孩子。我正在消除其中一个孩子的关系并将分离的父母传递给合并。提交事务时,会发出 UPDATE 语句,尝试使用 NULL 外键更新孤儿。
@Entity
public class Parent implements Serializable
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String desc;
//@ElementDependent
@OneToMany(mappedBy="parent",
cascade=CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE/*,orphanRemoval=true, fetch=FetchType.EAGER*/)
private List<Child> childs = new ArrayList<Child>();
@Entity
public class Child implements Serializable
@Id private String desc;
@ManyToOne
private Parent parent;
public class ***Test extends TestCase
private EntityManager em;
private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("SSICTest", System.getProperties());
private Parent p;
private Child c;
private Child c2;
public void testRemove()
prepareObjects();
startTr();
em.persist(p);
commitTr();
startTr();
p = em.find(Parent.class, p.getId());
em.remove(p);
commitTr();
public void testMerge()
prepareObjects();
startTr();
em.persist(p);
commitTr();
//remove on detached
Child child = p.getChilds().get(0);
p.getChilds().remove(child);
child.setParent(null);
startTr();
em.merge(p);
commitTr();
startTr();
p = em.find(Parent.class, p.getId());
assertEquals(1, p.getChilds().size());
commitTr();
protected void prepareObjects()
p = new Parent();
c = new Child();
c2 = new Child();
p.setDesc("desc");
c.setDesc(Math.random()+"");
c2.setDesc(Math.random()+"");
p.getChilds().add(c);
c.setParent(p);
p.getChilds().add(c2);
c2.setParent(p);
void commitTr()
em.getTransaction().commit();
em.close();
void startTr()
em = factory.createEntityManager();
em.getTransaction().begin();
在上面的示例中,testRemove 可以正常工作,但 testMerge 方法不能,正如我在顶部所描述的那样。
如果我删除对 @ElementDependent 的评论,它的工作方式会有所不同。
testRemove 失败,因为 remove 没有级联到 Child 和 db 抛出的引用完整性异常,并且 testMerge 很好。
orphanRemoval=true, fetch=FetchType.EAGER 或 @ForeignKey(deleteAction=ForeignKeyAction.CASCADE) 关于子级的逆关系 也不帮忙。
请指教。非常感谢您的帮助!
【问题讨论】:
嗨拉尔斯!我添加了这个,但没有帮助@ManyToOne @JoinColumn(name="PARENT_ID", nullable=false, referencedColumnName="ID") private Parent parent;
您当前的映射设置在哪里?它在persistence.xml 文件中吗?否则,据我所知,需要更多注释才能使映射正常工作。属性映射到哪些数据库列的信息在哪里? (顺便说一句,不要使用“desc”作为属性名,因为它是一个保留的 SQL 字)
是的,映射在persistence.xml中
【参考方案1】:
@OneToMany(mappedBy="parent",
cascade=CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE,
orphanRemoval=true, fetch=FetchType.EAGER)
private List<Child> childs = new ArrayList<Child>();
@ManyToOne
private Parent parent;
将 orphanRemoval 设置为 true。See purpose of orphanRemoval
【讨论】:
将 orphanRemoval 设置为 true 不起作用,正如我所提到的。已发出 UPDATE 语句,尝试在 testMerge 方法中使用 NULL 外键更新孤儿!以上是关于JPA Merge 和 Remove 不会同时级联到子对象的主要内容,如果未能解决你的问题,请参考以下文章
为啥 delete-orphan 需要“全部级联”才能在 JPA/Hibernate 中运行?