2014-10-08 108 views
1

我使用SINGLE_TABLE继承策略在Java中的Hibernate,这里是设置:似乎无法摆脱NonUniqueObjectException

Class A 

@Cascade(CascadeType.DELETE_ORPHAN, CascadeType.ALL) 
List<B> Bs; 

B具有延伸B.巴有一个额外的领域sublcass巴是b不具有。我这样做的原因是只有Ba对象(这个数量少得多)应该关心这个额外的字段,并且我想避免在每个B对象上的开销。

在保存过程中,我们的设置方式是,我们必须更新前B对象字段(而不仅仅是更改引用)。所以我们不能做Bs列表=变更Bs列表,我们必须通过主键找到每个B并更新字段,所以像B.fields = changedB.fields

发生此异常的时间是在保存过程中,当一个前B对象需要被保存为带有额外字段的Ba时。相反的方向(将一个前Ba对象保存到B)很好,我可以将该额外字段设置为null或抛弃。但我似乎无法找到将B对象变成Ba的方法。

我已经试过

  • 从列表中删除了B和添加钡保存之前,也就是当我得到这个例外。
  • 我甚至尝试将所有从B到B的字段交换成需要变成B和副verca的字段,但那也不起作用,我得到了一个异常,因为我改变了这些对象的Pk 。

回答

1

Session flush the DML operation order是:

  • 插入
  • 更新
  • 集合元素的缺失集合元素
  • 插入删除

因此,即使删除了元素并添加了新元素,插入也会在删除之前运行,因此会抛出违反约束的异常。

要使其工作,你需要手动刷新,删除后添加新元素之前回到孩子们集合:

a.removeChild(b); 
session.flush(); 
a.addChild(ba); 

删除/的addChild是公用事业设置双向两侧如果在你的领域模型中是这种情况的话。

+0

不幸的是,我没有在我这样做的代码部分的会话上下文。我这样做的地方很简单,将收集的新列表设置为旧列表,以便hibernate可以保存新列表。那么没有其他办法可以将B对象设置为Ba(带有额外的字段)吗?我的意思是我只需要为我知道存在于数据库(和子类)中的字段添加额外的值,而不是在对象本身上。 – James 2014-10-08 20:31:26

+0

重新分配新集合将删除所有子项并添加新对象。这不是有效的,在你的情况下也是无效的。它导致先插入并在稍后删除。所以你需要推动你有Session的逻辑。 – 2014-10-09 04:21:13