Question

I'm new to Grails and I need to make some calculations when a "has-many" attribute changes, and I think the best place to do this is in the setter of the attribute, given that my attribute is a list the best place should be in the addTo and the removeFrom methods, I tried to override them but didn't worked.

So is this the best way of doing it? what's wrong with my code?

Here's the code:

Cicle.groovy

class Cicle {

String machine
int cicleValue

static hasMany = [measurements:Measurement]

static constraints = {
    machine blank:false 
    cicleValue nullable:false 
}

public void addToMeasurements(Measurement measurement){
    super.addToMeasurements(measurement)
    updateCalculations()
}

public void updateCalculations(){

    int sumCicles = 0

    measurements.each{ measurement ->
        sumCicles += measurement.cicleValue
    }

    cicleValue = sumCicles / measurements.size()
    this.save(failOnError: true) 
}
}

This is the exception I get:

No signature of method: com.rpc.mock.app.Cicle.addToMeasurements() is applicable for argument types: (com.rpc.mock.app.Measurement) values: [com.rpc.mock.app.Measurement : (unsaved)]
Possible solutions: addToMeasurements(com.rpc.mock.app.Measurement), addToMeasurements(java.lang.Object), getMeasurements(). Stacktrace follows:
Message: No signature of method: com.rpc.mock.app.Cicle.addToMeasurements() is applicable for argument types: (com.rpc.mock.app.Measurement) values: [com.rpc.mock.app.Measurement : (unsaved)]
Possible solutions: addToMeasurements(com.rpc.mock.app.Measurement), addToMeasurements(java.lang.Object), getMeasurements()
    Line | Method
->>   16 | addToMeasurements in com.rpc.mock.app.Cicle
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     43 | $tt__save         in com.rpc.mock.app.MeasurementController
|    200 | doFilter . . . .  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter          in grails.plugin.cache.web.filter.AbstractFilter
|   1145 | runWorker . . . . in java.util.concurrent.ThreadPoolExecutor
|    615 | run               in java.util.concurrent.ThreadPoolExecutor$Worker
^    744 | run . . . . . . . in java.lang.Thread

Thanks

Was it helpful?

Solution

As you're dealing with domain objects, GORM supports the registration of events as methods that get fired when certain events occurs such as deletes, insertsand updates:

beforeInsert - Executed before an object is initially persisted to the database
beforeUpdate - Executed before an object is updated
beforeDelete - Executed before an object is deleted
beforeValidate - Executed before an object is validated
afterInsert - Executed after an object is persisted to the database
afterUpdate - Executed after an object has been updated
afterDelete - Executed after an object has been deleted
onLoad - Executed when an object is loaded from the database

Then, you can add updateCalculations() in your domain object like that:

static constraints = {
    machine blank:false 
    cicleValue nullable:false 
}

def beforeUpdate() { updateCalculations()  }

As a general good design practice, it's better to keep logic implementation out from domains object and Grails allows to inject services into domains (POGO).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top