如何使用GORM事件正确更新一对多关联

时间:2014-05-20 15:42:17

标签: hibernate grails gorm

我正在尝试使用GORM事件beforeInsertbeforeUpdate更新Grails中的一对多关联。目前beforeInsert似乎正在运行,但beforeUpdate总是在hibernate flush上抛出TransientObjectException

以下列方式映射域(一个例子,但希望足以得到这个想法):

class Part {

   String xml

   static hasMany = [screws: Screws]

   static mapping = {
      screws cascade: "all-delete-orphan"
   }
}

class Screw {
   static belongsTo = Part
}

我的更新和插入基本上做同样的事情,这个方法从beforeInsertbeforeUpdate调用(再次是一个代表性的例子):

private void augmentPartWithScrews() {
   screws?.clear()
   Set<Screw> parsedScrews = service.parseXmlAndReturnSetofScrews(xml)
   parsedScrews.each {
      addToScrews(it)
   }
}

我所看到的是,当我创建一个新的Part它可以工作时,但是当我更新Part以便删除螺丝时,我在Hibernate的TransientObjectException类中获得ForeignKeys。我做了一些调试,发现在创建Part的新实例时,对象作为已保存的实例进入函数getEntityIdentifierIfNotUnsaved方法,但在更新时它们作为未保存的实例进入,因此是异常。

这是Grails 2.3.7和Hibernate插件3.6.10.10

1 个答案:

答案 0 :(得分:1)

我们发现尝试在beforeInsertbeforeUpdate方法中执行插入或删除操作可能会非常痛苦。 withNewSession几乎总是必不可少的,因为您在刷新会话时有效地尝试修改会话,从而导致Hibernate无法混淆。但是,使用withNewSession时,screws已加载到其他会话中,因此将在此新会话中分离。

有人认为在这种情况下您可以做的是将逻辑移动到beforeValidate方法中,该方法与会话刷新行为无关。有一张门票可以添加afterValidate,这更符合您的要求(但它还没有)。

但是,在这种情况下,最好只是反转极性并进行服务更新/保存新部件并解析并添加螺钉,而不是尝试将逻辑放入域对象。