更新:我重写了这个问题,尽可能提高意识并提供最多的信息。
我有以下内容:
@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”
答案 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);
}
}
}