Spring/Hibernate替换一组级联对象

Spring/Hibernate替换一组级联对象,hibernate,spring,replace,set,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; @Man

更新:我重写了这个问题,以尽可能地解释问题,并提供最多的信息

我有以下资料:

@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);
}
案例2:修改一个傻瓜条并持久化一个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);

案例1中的错误消息现在是“not null属性引用null或瞬态值:傻瓜吧.foo”

它似乎完全按照您的指示执行:

ObjectOne obj1=findInDatabase()

加载持久对象

obj1.addSet(objTwoSet)

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

sessionFactory.getCurrentSession().saveOrUpdate(obj1)

不必要地保存或更新()对象。对象已附加到会话,因此在提交封闭事务时,其状态将正确保持。你可以取消这一行

要清除集合中的现有内容并添加所有新内容,您应该执行以下操作:

obj1.clearSet();
obj1.addSet(objTwoSet);
更新:在Hibernate中,集合不会被视为单个离散对象。这只是一组实体,所以当你说“从数据库中删除第一个集合”时,你实际上是说“从数据库中删除第一个集合中包含的所有实体”或“将第一个集合中包含的所有实体与数据库中给定的对象断开关联”

对于前者,您将使用,并查看参考指南演示的

对于后者,您只需完全按照您正在做的操作,但如果是双向关系,您还必须正确设置另一端。因此,不是简单的:

obj1.addSet(objTwoSet);
你需要像这样的东西:

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

这很可能是你的问题。让对象模型处于断开状态永远都不好。

它似乎完全按照您的要求执行:

ObjectOne obj1=findInDatabase()

加载持久对象

obj1.addSet(objTwoSet)

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

sessionFactory.getCurrentSession().saveOrUpdate(obj1)

不必要地保存或更新()对象。对象已附加到会话,因此在提交封闭事务时,其状态将正确保持。你可以取消这一行

要清除集合中的现有内容并添加所有新内容,您应该执行以下操作:

obj1.clearSet();
obj1.addSet(objTwoSet);
更新:在Hibernate中,集合不会被视为单个离散对象。这只是一组实体,所以当你说“从数据库中删除第一个集合”时,你实际上是说“从数据库中删除第一个集合中包含的所有实体”或“将第一个集合中包含的所有实体与数据库中给定的对象断开关联”

对于前者,您将使用,并查看参考指南演示的

对于后者,您只需完全按照您正在做的操作,但如果是双向关系,您还必须正确设置另一端。因此,不是简单的:

obj1.addSet(objTwoSet);
你需要像这样的东西:

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

这很可能是你的问题。让对象模型处于断开状态永远都不好。

尝试以下实现:

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

  public void addSet(Set<ObjectTwo> newSet){
    obj2.clear();
    obj2.addAll(newSet);
  }
}
公共类ObjectOne{
@OneToMany(cascade=CascadeType.ALL,orphan=true)
设置obj2;
公共无效地址集(集合新闻集){
obj2.clear();
obj2.addAll(新闻集);
}
}
关联是双向的,即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);
    }
  }
}
公共类ObjectOne{
@OneToMany(cascade=CascadeType.ALL,orphan=true)
设置obj2;
公共无效地址集(集合新闻集){
for(ObjectTwo:obj2){
2.setObjectOne(空);
}
obj2.clear();
for(ObjectTwo:newSet){
二、设置对象一(本);
obj2.增加(两个);
}
}
}

尝试以下实现:

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

  public void addSet(Set<ObjectTwo> newSet){
    obj2.clear();
    obj2.addAll(newSet);
  }
}
公共类ObjectOne{
@OneToMany(cascade=CascadeType.ALL,orphan=true)
设置obj2;
公共无效地址集(集合新闻集){
obj2.clear();
obj2.addAll(新闻集);
}
}
关联是双向的,即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);
    }
  }
}
公共类ObjectOne{
@OneToMany(cascade=CascadeType.ALL,orphan=true)
设置obj2;
公共无效地址集(集合新闻集){
for(ObjectTwo:obj2){
2.setObjectOne(空);
}
obj2.clear();
for(ObjectTwo:newSet){
二、设置对象一(本);
obj2.增加(两个);
}
}
}

addSetmethod到底做什么?在本例中,它是一个虚拟方法,可以向ObjectOne添加一组ObjectTwo。您可以向我们展示您的xml映射代码吗?或者注释配置?我已经为Object2设置了(cascade=CascadeType.ALL)。我是否应该使用另一种替代而不是合并的方法?您是否尝试过将
DELETE-ORPHAN
ALL
一起使用?
addSet
方法到底是做什么的?在本例中,它是一个虚拟方法,可以向ObjectOne添加一组ObjectTwo。您可以向我们展示您的xml映射代码吗?或者注释配置?我已经为Object2设置了(cascade=CascadeType.ALL)。我是否应该使用另一种替代而不是合并的方法?您是否尝试过将
DELETE-ORPHAN
ALL
一起使用?此外,如果我必须调用clearSet方法,然后调用另一个方法来添加新的集合,那么我必须撤回现有集合并手动比较它们,以查看是否有差异。换句话说,我不想清除然后重新添加相同的集合。我假设hibernate有一些方法可以自动为您完成所有这一切?我正在尝试后一种方法。谢谢你的建议,很有意义!我很快会尝试一下,看看这是否能解决问题。结果证明它不起作用。我不能设置另一个