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

时间:2017-08-14 22:00:56

标签: 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的父级时不会保存“jf”,即使aRealField1确实保存得很好。

我假设GORM没有将此对象识别为脏并且需要持久性,因为它是从两个现有对象创建的,即使它是由这两个现有对象组成的新对象。但在这种情况下,我没有看到强制这种级联保存的方法。这一切都与Grails 2.2.4一起使用。

更新

这似乎是交易问题的核心。我们有SomeParentClass的控制器,其中收到请求以保存对象。这反过来在'withTransaction'闭包内调用Transactional服务类,以允许我们在发生任何错误时回滚事务。该服务进行了大量的保存,我们希望能够在任何错误上回滚整个集合。

如果我们删除服务上的@Transactional注释和控制器中的withTransaction闭包,那么上面的JoinedField类保存得很好。但是,当发生错误时,我们缺少整套更改的回滚。

我们已经删除了控制器中的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
        }
    }
}

有关为什么在事务服务中无法保留但在删除该注释时仍然存在的任何想法?

1 个答案:

答案 0 :(得分:0)

通过将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版本。