hibernate - Grails 3-具有复合键的域对象并不总是保存

标签 hibernate grails gorm composite-primary-key

我们最近从Grails 2.2.4升级到了3.2.2。从那时起,在尝试使用复合键持久存储新创建的对象时,我们一直遇到问题。

假设我们有一个名为SomeField的域对象。

class SomeField {

    static belongsTo = [parentClass : SomeParentClass]

    static hasMany = [joinedFields : JoinedField]

    joinedFields fetch:'join', cascade:'all-delete-orphan'

}

还有一个名为JoinedField的域对象,该对象属于其两个SomeField成员之一。它使用两个字段来创建其组合键。
class JoinedField {

    SomeField field1
    SomeField field2

    static belongsTo = [field1: SomeField]

    static mapping = {
        id composite: ['field1', 'field2']

        columns {
            field1  column:'F1_ID'
            field2  column:'F2_ID'
        }

        version false
    }

    static contraints = {
        field1(nullable:false)
        field2(nullable:false)
    }

    def getPk = {
        ['field1':field1.id, 'field2':field2.id]
    }
}

Field2始终已经存在于数据库中,并在其中添加JoinedField对象时从那里查找。

当field1的父项全部是新父项并且我们将其保存时,将保存field1并使用两个键按预期持久化JoinedField对象。但是,如果已保存field1的父级,然后将JoinedField对象添加到现有的field1对象或新的field1对象中并保存,则JoinedField对象不会持久保存。

例:
someParent.addToFields( aRealField1 )

def jf = new JoinedField()
aRealField1.addToJoinedFields( jf )
jf.field2 = SomeField.findById( 1234 )

someParent.save()

因此-如果aRealField1属于尚未保存的父项,则保存aRealField1的父项时将保留'aRealField1'和'jf'。如果field1的父级已经存在,那么即使保存aRealField1也可以,但保存aRealField1的父级时不会保存'jf'。

我认为GORM不会将其识别为脏对象并需要持久性,因为它是由两个现有对象创建的,即使它本身是由这两个现有对象组成的新对象。但是在这种情况下,我看不出有办法强制进行这种级联保存。所有这些都与Grails 2.2.4一起使用。

更新:

似乎这是核心的交易问题。我们有一个SomeParentClass的 Controller ,在该 Controller 中接收到保存对象的请求。依次调用“withTransaction”闭包内的Transactional服务类,以允许我们在发生任何错误时回滚事务。该服务可节省大量费用,我们希望保留在发生任何错误时回退整个集合的功能。

如果我们删除服务上的@Transactional批注以及 Controller 中的withTransaction闭包,那么上面的JoinedField类将保存得很好。但是,当发生错误时,我们将缺乏对完整更改集的回滚。

我们已经删除了 Controller 中的withTransaction,并且当该服务仍被注释为Transactional时可以处理该服务中的回滚,但是JoinedField对象仍然无法如所描述的那样持久。

例:
仅在服务中使用回滚的代码是最干净的:
import grails.transaction.Transactional

@Transactional
class BuildObjectService {

    def buildObject(def json) {
        try {
            // build the object from json representation
        }
        catch( Exception e ) {
            transactionStatus.setRollbackOnly()
            throw e
        }
    }
}

关于为什么为什么在事务服务中这种方法无法持续但在删除该注释时仍能正常运行的任何想法?

最佳答案

通过将org.grails:grails-datastore-gorm *,org.grails:grails-datastore-core和org.grails.plugins:hibernate5升级到最新的6.1.6.RELEASE版本,解决了此问题。

这将替换org.grails:grails-depenedencies引入的6.0.3版本。

关于hibernate - Grails 3-具有复合键的域对象并不总是保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45683674/

相关文章:

grails - Grails-从数据库中检索新实例

grails - 单向1:M关系默认情况下使用联接表

java - JBoss 和不同版本的 Hibernate

grails - 如何传递列表值以使分页正确呈现?

java - 如何使用 jpa (hibernate) 从表中仅选择 postgres jsonb 列

unit-testing - 使用服务和插件依赖项测试自定义 Grails Taglib

java - 仅告诉 Grails 使用哪个 JDK

hibernate - 是否可以在不获取引用域的情况下保存新的Grails域实例?

spring - 在 Hibernate 的 EmptyInterceptor 中注入(inject) JPA 的实体管理器

Hibernate envers Enumeration审计异常