Spring / Hibernate替换了一组级联对象

时间:2011-12-22 17:39:13

标签: hibernate spring replace set

更新:我重写了这个问题,尽可能提高意识并提供最多的信息。

我有以下内容:

@Entity
public class FooLnkBar implements java.io.Serializable {
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "SomeID", nullable = false)
    private Foo foo;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "OtherID", nullable = false)
    private Bar bar;
}

@Entity
public class Foo implements java.io.Serializable {
    @OneToMany(orphanRemoval=true, cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "foo")
    private Set<FooLnkBar> fooLnkBars = new HashSet<FooLnkBar>(0);
}

案例1:通过持久化FooLnkBar来保存所有内容

 // This correctly saves everything into the database in one shot
 Foo foo = new Foo();
 Bar bar = new Bar();
 FooLnkBar flb = new FooLnkBar();
 flb.setFoo(foo);
 flb.setBar(bar);
 persist(flb);

案例2:修改FooLnkBar并保留Foo

 // Load a Foo from the database and get the set of FooLnkBars
 Foo foo = loadFooFromDatabase();
 Set<FooLnkBar> fooLnkBars = foo.getFooLnkBars();

 // Delete all existing FooLnkBar objects. Alternatively use removeAll()
 Iterator<FooLnkBar> it = fooLnkBars.iterator();
 while (it.hasNext()) {
   FooLnkBar o = it.next();
   it.remove();
 }

 // Add some new FooLnkBars
 Foo foo = new Foo();
 Bar bar = new Bar();
 FooLnkBar flb = new FooLnkBar();
 fooLnkBars.add(flb);
 foo.setFooLnkBars(fooLnkBars);

 // Save all changes
 persist(foo);

案例2不起作用。由于cascadeType,这也删除了FooLnkBar所在的Foo,因此删除了案例2中的整个Foo对象。这很糟糕。

此外,我想确保当我尝试保留它时,hibernate不会将Foo视为重复行,因为FooLnkBar是另一个表中的值。

如果我从数据库中删除Foo,也应该从数据库中删除FooLnkBar。

如果我从数据库中删除FooLnkBar,则不应从数据库中删除Foo。

我正在寻找让所有案件都有效的方法。

更新:更改此修复案例2但违反案例1:

   @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
   @JoinColumn(name = "SomeID", nullable = false)
   private Foo foo;

案例1中的错误消息现在是“非null属性引用空值或瞬态值:FooLnkBar.foo”

2 个答案:

答案 0 :(得分:2)

它似乎完全按照你所说的去做:

  

ObjectOne obj1 = findInDatabase();

加载持久对象。

  

obj1.addSet(objTwoSet);

将集合的内容添加到对象的现有集合中(从而“合并”这两个集合)。

  

sessionFactory.getCurrentSession()saveOrUpdate(OBJ1);

不必要的saveOrUpdate()对象。该对象已附加到会话,因此当封闭事务提交时,其状态将正确保留。你可以取消这一行。

为了清除集合的现有内容并添加所有新内容,您应该这样做:

obj1.clearSet();
obj1.addSet(objTwoSet);

更新:在Hibernate中,Set不被视为单个离散对象。它只是一组实体,所以当你说“从数据库中删除第一个Set”时,你实际上是在说“从数据库中删除第一个集合中包含的所有实体”之一或者“取消关联中包含的所有实体”。数据库中给定对象的第一个集合。“

对于前者,您可以使用orphanRemoval attribute of @OneToMany,并查看参考指南中演示的prototypical parent/child relationships

对于后者,你只是做你正在做的事情,但如果它是双向关系,你还必须正确设置另一端。所以不是简单的:

obj1.addSet(objTwoSet);

你需要这样的东西:

for (ObjectTwo o : obj1.getSet()) {
    o.setObjectOne(null);
}
obj1.addSet(objTwoSet);

这很可能是你的问题。将对象模型置于破碎状态永远不可能。

答案 1 :(得分:1)

尝试以下实施:

public class ObjectOne{
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true)
  Set<ObjectTwo> obj2;

  public void addSet(Set<ObjectTwo> newSet){
    obj2.clear();
    obj2.addAll(newSet);
  }
}

关联是双向的,即ObjectTwo是否也引用了ObjectOne?如果是这样,在清除obj2集之前,还必须将此引用设置为null。

public class ObjectOne{
  @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true)
  Set<ObjectTwo> obj2;

  public void addSet(Set<ObjectTwo> newSet){
    for (ObjectTwo two : obj2) {
      two.setObjectOne(null);
    }
    obj2.clear();
    for (ObjectTwo two : newSet) {
      two.setObjectOne(this);
      obj2.add(two);
    }
  }
}