Search code examples
grailsgroovygrails-orm

Derived Properties using aggregate functions in Grails


I'm trying to create derived properties based on contained objects.

Example below:

class Generation {

    String name

    DateTime productionStart

    DateTime productionEnd

    static belongsTo = [line: Line]

    static hasMany = [bodyStyles: BodyStyle, engines: Engine, models: Model]

    static constraints = {
        line nullable: false
        name nullable: false, unique: ['line'], maxSize: 255, blank: false
    }

    static mapping = {
        // I've tried but this solution causes errors
        productionStart formula: 'MIN(engines.productionStart)'
        // I've tried but this solution causes errors
        productionEnd formula: 'MAX(engines.productionEnd)'
    }
}

class Engine {

    String name

    Integer horsePower

    DateTime productionStart

    DateTime productionEnd

    static belongsTo = [generation: Generation]

    static hasMany = [models: Model]

    static constraints = {
        generation nullable: false
        name nullable: false, unique: ['generation', 'horsePower'], maxSize: 255, blank: false
        horsePower nullable: false
        productionStart nullable: false
        productionEnd nullable: true
    }

    static mapping = {
        productionStart type: PersistentDateTime
        productionEnd type: PersistentDateTime
   }
}

I've readed Derived Properties Documentation but my case is a little bit more complicated than formulas not associated with complex objects.

The solution that you can find in the code above results in an error::

Caused by GrailsTagException: Error executing tag : Error evaluating expression [Generation.findAll()] on line [23]: could not execute query; SQL [select this_.id as id22_0_, this_.version as version22_0_, this_.line_id as line3_22_0_, this_.name as name22_0_, MAX(engines.productionEnd) as formula0_0_, MIN(engines.productionStart) as formula1_0_ from generation this_]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query


Solution

  • Another way to try it is to create a getter instead of derived properties:

    class Generation {
    
        String name
    
        DateTime productionStart
    
        DateTime productionEnd
    
        static transients = ['productionStart','productionEnd']
    
        static belongsTo = [line: Line]
    
        static hasMany = [bodyStyles: BodyStyle, engines: Engine, models: Model]
    
        static constraints = {
            line nullable: false
            name nullable: false, unique: ['line'], maxSize: 255, blank: false
        }
    
    
        DateTime getProductionStart() {
          def datetime = Engine.createCriteria().get {
            eq('generation',this)
            projections {
              min('productionStart')
            }
          }
    
          return datetime
    
        }
    
        DateTime getProductionEnd() {
          def datetime = Engine.createCriteria().get {
            eq('generation',this)
            projections {
              max('productionEnd')
            }
          }
    
          return datetime
        }
    
    }