java - JPA Merge 和 Remove 不会同时级联到子对象

标签 java jpa orm persistence openjpa

我在商业项目中使用 Open JPA,并希望利用级联的 Parent->Child 删除和合并。

我模拟了一个显示问题的工作代码。

我有一个带有一些 child 的持久父对象。我正在消除一个 Children 的关系,并传递分离的 Parent 进行合并。当提交事务时,发出更新语句,尝试使用 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 StackOverflowTest 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) 在 child 的反向关系上 也不帮了。

请指教。非常感谢您的帮助!!

最佳答案

 @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

关于java - JPA Merge 和 Remove 不会同时级联到子对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13495695/

相关文章:

java - 如何处理空参数的 JPA 查询方法中的所有枚举值

python - Django 模型检索相同的结果

hibernate - JPA:合并分离对象的有效方法是什么?

java - 在jboss服务器7.0中部署war文件

java - 如何在android中使用java检查变量是否包含双值或空值

java - 如何在资源中定义组合字符串?

java - JPA 分离实体传递到持久化

sql - Sequelize findAll 多对多条件

c# - 使用 Entity Framework 向模型添加方法

带有 ISO-8859-1 的 Java 快速流复制