grails domain object unexpectedly saved during validation

534 Views Asked by At

Considering the following domain classes :

class EnrichmentConfig {

    String name
    String description
    String concept
    List fields = []

    static hasMany = [fields: FieldConfig]

    static constraints = {
        name(maxSize: 60, blank: false, nullable: false, unique: true)
        concept(maxSize: 255, blank: false, nullable: false)
        description(nullable: true, blank: true)
        fields(nullable: false, validator: { fields, enrichmentConfig ->
            if (fields?.isEmpty()) {
                return ['empty']
            } else {
                return true
            }
        })
    }

    static mapping = {
        description(type: 'text')
        fields(cascade: "all-delete-orphan")

        sort('name')
    }
}

and

class FieldConfig {

    List providers = []

    static hasMany = [providers: String]

    static belongsTo = [mainConfig: EnrichmentConfig]

    static constraints = {

        providers(nullable: false, validator: { providers, fieldConfig ->
            // some custom validation
        })
    }

    static mapping = {
        providers(cascade: 'all-delete-orphan', lazy: false)
    }
}

Here the code I use to update an EnrichmentConfig instance in the associated controller:

def update = {

    def enrichmentConfig = EnrichmentConfig.get(params.long('id'))
    if (enrichmentConfig) {

        enrichmentConfig.properties = params

        if (enrichmentConfig.validate()) {
            if (enrichmentConfig.save(flush: true, failOnError: true)) {
                    flash.message = "${message(code: 'enrichmentConfig.updated.message', args: [enrichmentConfig.name])}"
                    redirect(controller: 'enrichment')
                }
        } else {
            // re-validation to attach an error object to each eroneous fieldConfig
            enrichmentConfig.fields?.each { it.validate() }
        }
        render(view: 'fields', model: getFieldsModel(enrichmentConfig))
        return
    } else {
        flash.message = "${message(code: 'enrichmentConfig.not.found.message', args: [params.id])}"
        redirect(controller: 'enrichment')
    }
}

I've noticed that when I validate an instance of EnrichmentConfig to be updated, associated FieldConfig instances are unexpectedly saved in the database even though they are invalid. In fact, in debug ste-by-step mode, while enrichmentConfig.validate() is executed, the following appears in the console:

    Hibernate: 
    update
        field_config_providers 
    set
        providers_string=? 
    where
        field_config_id=? 
        and providers_idx=?

How can this be happening? What am I doing wrong? I should specify that I use grails 1.3.7.

Thanks in advance for your help.

2

There are 2 best solutions below

0
On

I suggest using a service to save your objects. First, check all the objects for validity using the validate() method.

Then, save the objects in the order in which they depend or in the hierarchy they follow.

0
On

This is just a guess but possibly someplace to start. I don't pretend to understand when Hibernate decides to flush sessions and partially save data and the like. But what I do know is that putting all write related calls in a service saves me a ton of grief over time.

Try moving some of your update method to a service and see if you have better luck. My hunch is that possibly, hibernate needs to persist some of the data to do other stuff and if it were in a transactional service, that write would rollback once the RuntimeException is thrown.