一对多关系JPA / Hibernate删除链接 [英] One to Many relationship JPA/Hibernate removing links

查看:132
本文介绍了一对多关系JPA / Hibernate删除链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有双向关系设置,如下所示:

  class Child {
@ManyToOne
@JoinTable (name =CHILDREN_WITH_PARENT,
joinColumns = {@JoinColumn(name =CHILD_ID)},
inverseJoinColumns = {@JoinColumn(name =PARENT_ID)}

私人父母;
}

类父母{
@OneToMany(mappedBy =parent,cascade = CascadeType.ALL)
Set< Child> childrens = new HashSet< Child>();

public void persistOrMerge(){
EntityManager em = entityManager();
em.getTransaction()。begin();
尝试{
if(em.contains(this))
return;
if(id == null || id == 0){
this.setCreatedDate(new Date());
em.persist(this);
} else {
Parent prev = em.find(Parent.class,this.id);
if(prev == null){
em.persist(this);
} else {
this.setCreatedDate(new Date());
em.merge(this);
}
}
em.flush();
em.getTransaction()。commit();

} finally {
em.close();




code


$ b < (GWT + EntityProxy)

  Set< ChildProxy> children = new HashSet< ChildProxy>(); 
if(childIsNew)
child = request.create(Children.class)
else
child = request.edit(oldChild)
children.add(child);
//如果子项被删除,它们不包含在set
中//我们将发送回服务器
parent.setChildren(children)
parent.persistOrMerge();

此代码仅适用于添加新的子项。即使父母课程收到一个空的儿童套装,从父母中移除孩子也不起作用。



您可以告诉我在哪里丢失了什么?



感谢!

解决方案

我会先说这是一个非常糟糕的主意,实体是使用实体的实体直接经理。



EntityManager.merge()方法返回实际的合并实例,这意味着在您的代码中,当您发出

  em.merge(this)

您没有保证合并的实例不再与this相对应,从这一点开始,您可能会看到各种逻辑问题。



如果你不认为这是这样的一个重大的问题,你应该通过打开关系的OneToMany一边的孤儿删除来解决你的问题,前提是这些孩子没有被用在其他关系中的任何其他地方。

  @OneToMany(mappedBy =parent,cascade = CascadeType.ALL,orphanRemoval = true)
Set< Child> childrens = new HashSet< Child>();

JPA 2.0规范声明:

指定为OneToOne或OneToMany的关联支持使用orphanRemoval
选项。当orphanRemoval生效时,以下行为适用:


  • 如果一个实体是
    的目标,
    关系(通过将
    关系设置为null或从关系
    集合中除去
    实体),删除操作
    将应用于实体
    孤儿。删除操作是在冲洗
    操作时应用的
    。 orphanRemoval
    功能适用于由其父实体私有拥有

    实体。便携式
    应用程序必须否则不能
    取决于特定的
    删除顺序,并且不得重新分配
    实体,该实体已被孤立为
    另一种关系或
    试图坚持它。如果被孤立的实体
    是已分离的,新的或
    被删除的实体,则
    orphanRemoval的语义不适用。

  • 如果删除操作应用于
    a托管来源实体,则删除
    操作将按照
    与第3.2.3节的规则(和
    )级联至
    关系目标因此没有必要为
    关系指定
    cascade = REMOVE)[20]。

    I have bidirectional relationship setup as follows:

    class Child{
        @ManyToOne
        @JoinTable(name = "CHILDREN_WITH_PARENT", 
                joinColumns = {@JoinColumn(name = "CHILD_ID")}, 
                inverseJoinColumns = {@JoinColumn(name = "PARENT_ID")}
        )
        private Parent parent;
    }
    
    class Parent{
        @OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
        Set<Child> childrens = new HashSet<Child>();
    
        public void persistOrMerge() {
            EntityManager em = entityManager();
            em.getTransaction().begin();
            try {
                if (em.contains(this))
                    return;
                if (id == null || id == 0) {
                    this.setCreatedDate(new Date());
                    em.persist(this);
                } else {
                    Parent prev = em.find(Parent.class, this.id);
                    if (prev == null) {
                        em.persist(this);
                    } else{
                        this.setCreatedDate(new Date());
                        em.merge(this);
                    }
                }
                em.flush();
                em.getTransaction().commit();
    
            }  finally {
                em.close();
    
            }
        }
    
    }
    

    On my client side I have following code (GWT + EntityProxy)

    Set<ChildProxy> children  = new HashSet<ChildProxy>();
    if(childIsNew)
       child = request.create(Children.class)
    else
       child = request.edit(oldChild)
    children.add(child);
    //If children are deleted, they are not contained in the set
    //we are sending back to server
    parent.setChildren(children)
    parent.persistOrMerge();
    

    This code only works for adding new children. Removing of children from parent does not work even if parent class receives an empty children set. The linkages in JOIN table are not removed.

    Can you please tell where I am missing something?

    Thanks!

    解决方案

    I will start by saying that is a really bad idea that the entity is the one using the entity manager directly.

    The EntityManager.merge() method returns the actual merged instance, this implies that in your code, when you issue

    em.merge(this)
    

    You have no guarantee whatsoever that the merged instance corresponds to "this" anymore, and from that point on you may see all kinds of logical problems.

    If you do not think this is such a big deal, your problem should be solved by turning on orphan removal on the OneToMany side of the relationship, provided that the children are not being used anywhere else in other relationships. Otherwise you will have to do the merging manually.

    @OneToMany(mappedBy="parent", cascade=CascadeType.ALL, orphanRemoval=true)
    Set<Child> childrens = new HashSet<Child>();
    

    The JPA 2.0 specification states that

    Associations that are specified as OneToOne or OneToMany support use of the orphanRemoval option. The following behaviors apply when orphanRemoval is in effect:

    • If an entity that is the target of the relationship is removed from the relationship (by setting the relationship to null or removing the entity from the relationship collection), the remove operation will be applied to the entity being orphaned. The remove operation is applied at the time of the flush operation. The orphanRemoval functionality is intended for entities that are privately "owned" by their parent entity. Portable applications must otherwise not depend upon a specific order of removal, and must not reassign an entity that has been orphaned to another relationship or otherwise attempt to persist it. If the entity being orphaned is a detached, new,or removed entity, the semantics of orphanRemoval do not apply.
    • If the remove operation is applied to a managed source entity, the remove operation will be cascaded to the relationship target in accordance with the rules of section 3.2.3, (and hence it is not necessary to specify cascade=REMOVE for the relationship)[20].

    这篇关于一对多关系JPA / Hibernate删除链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆