【问题标题】:Spring / Hibernate replacing a Set of cascaded objectsSpring / Hibernate 替换一组级联对象
【发布时间】:2012-01-26 07:48:11
【问题描述】:

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

我有以下几点:

@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对象都被删除了。这很糟糕。

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

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

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

我正在寻找一种让所有案例都能正常工作的方法。

更新:更改此设置修复了案例 2,但破坏了案例 1:

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

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

【问题讨论】:

  • addSet 方法到底是做什么的?
  • 在这个例子中这是一个虚拟方法,它将一组 ObjectTwos 添加到 ObjectOne
  • 您能告诉我们您的 xml 映射代码吗?还是注解配置?
  • 我为 ObjectTwo 设置了 (cascade = CascadeType.ALL)。有没有我应该使用的不同的替换而不是合并?
  • 你试过DELETE-ORPHANALL一起使用吗? stackoverflow.com/questions/306144/…

标签: hibernate spring replace set


【解决方案1】:

它似乎完全按照你告诉它的做:

ObjectOne obj1 = findInDatabase();

加载一个持久对象。

obj1.addSet(objTwoSet);

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

sessionFactory.getCurrentSession().saveOrUpdate(obj1);

不必要地 saveOrUpdate() 对象。该对象已附加到会话,因此当封闭事务提交时,其状态将正确持久化。你可以取消这条线。

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

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

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

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

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

obj1.addSet(objTwoSet);

你需要这样的东西:

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

这很可能是您的问题。永远不要让您的对象模型处于损坏状态。

【讨论】:

  • 另外,如果我必须调用 clearSet 方法,然后调用不同的方法来添加新集合,我将不得不撤回现有集合并手动比较它们以查看如果有差异。换句话说,我不想清除然后重新添加相同的集合。我认为 hibernate 有某种方式可以自动为您完成所有这些工作?
  • 我正在尝试做后者。谢谢建议,有道理!我会尽快尝试一下,看看是否能解决问题。
  • 原来没有用。我无法将其他 Objects 属性设置为 null,因为它是必填字段,并且会从数据库中引发约束错误。
  • 设置 orphanRemoval 的属性也不起作用。我还从 Set 的数据库中获得了一个 UniqueConstraint 异常(一个条目已经存在)。
  • 如果关系不能为空,那么你要么必须给它一个不同的“所有者”,要么删除它。违反唯一约束意味着它听起来像:您有某种唯一约束,并且您正在尝试添加一个违反约束的对象。这与您最初的问题并没有真正的关系。
【解决方案2】:

尝试以下实现:

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);
    }
  }
}

【讨论】:

  • Tscho,我很抱歉,但我认为我最初的问题写得不好。请查看更新版本,我的情况可能更有意义。
猜你喜欢
  • 2017-02-24
  • 1970-01-01
  • 2014-11-16
  • 1970-01-01
  • 2019-07-11
  • 1970-01-01
  • 2016-05-03
  • 2011-03-13
  • 1970-01-01
相关资源
最近更新 更多