简体   繁体   中英

Grails 3 - domain object with composite key not always saving

We recently upgraded from Grails 2.2.4 to 3.2.2. Since then, we've been having issues when trying to persist a newly created object with a composite key.

Let's say we have a domain object called SomeField.

class SomeField {

    static belongsTo = [parentClass : SomeParentClass]

    static hasMany = [joinedFields : JoinedField]

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

}

There's another domain object called JoinedField which belongsTo one of its two SomeField members. It uses both fields to create its composite key.

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 always exists already in the database and gets looked up from there when adding it the JoinedField object.

When field1's parent is all new and we save it, field1 is saved and the JoinedField object is persisted with the two keys as expected. When field1's parent has already been saved, however, and then the JoinedField object is added to an existing field1 object or a new field1 object and saved, the JoinedField object is not persisted.

Example:

someParent.addToFields( aRealField1 )

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

someParent.save()

So -- if aRealField1 belongs to a parent not yet saved, then 'aRealField1' and 'jf' are persisted when aRealField1's parent is saved. If field1's parent already exists, then 'jf' is not saved when aRealField1's parent is saved, even though aRealField1 does get saved fine.

I assume GORM is not recognizing this object as dirty and needing persistence because it's created from two existing objects, even though it is a new object itself made of those two existing objects. But I don't see a way to force this cascading save to happen in this case. It was all working with Grails 2.2.4.

Update:

It seems that there is a transaction issue at the heart of this. We have a controller for SomeParentClass where the request is received to save the object. That in turn calls a Transactional service class within a 'withTransaction' closure to allow us to roll back the transaction if any errors occur. The service does numerous saves and we want to keep the ability to roll back the whole set on any error.

If we remove the @Transactional annotation on the service, and the withTransaction closure in the controller, then the JoinedField class above saves just fine. However, we then are lacking the rollback of the complete set of changes when an error occurs.

We have removed the withTransaction in the controller and can handle the rollback in the service when it is still annotated as Transactional, but then the JoinedField object still fails to persist as described.

Example: Code with rollback only in service is cleanest:

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

Any ideas on why this fails to persist when within a transactional service but does fine when that annotation is removed?

Resolved this issue by upgrading org.grails:grails-datastore-gorm*, org.grails:grails-datastore-core and org.grails.plugins:hibernate5 to the latest 6.1.6.RELEASE version.

This replaces the 6.0.3 versions that the org.grails:grails-depenedencies was pulling in.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM