Search code examples
hibernategrailsgrails-ormnamed-query

Grails use inherited property within named query


I want to use an inherited property within a named query of a derived instance, in order that I can provide a custom sort of the results. I am getting an error.

package com.example

class Ticket {
    // User is defined elsewhere
    static belongsTo = [user : User]
    String idNumber
}

class SeasonTicket extends Ticket {

    // some custom properties go here

    static namedQueries = {
        locateOrderedSeasonTicketsByUser { user ->
            // all derived instances are in the same table, hence return only the correct derived instances
            eq("class", "com.example.SeasonTicket")

            // return a match on user
            user {
                idEq(user.id)
            }

            // implement custom order
            order "customProperty"
        }
    } << Ticket.namedQueries
}

The final line allows any inherited named queries defined in the base class to be used.

I get the following error when running an integration test that calls:

SeasonTicket.locateOrderedSeasonTicketsByUser(someUserInstance)

No signature of method: com.example.User.call() is applicable for argument types: (com.example.SeasonTicket$__clinit__closure2_closure3_closure4) values: [com.example.SeasonTicket$__clinit__closure2_closure3_closure4@31ee7d7a] Possible solutions: wait(), last(), save(), any(), getAll(), wait(long)

The integration test was my first attempt at a simple test :

void "SeasonTicket.locateOrderedSeasonTicketsByUser finds an object"() {
    given:
    def seasonTicket = new SeasonTicket()
    def user = new User()       
    user.addToSeasonTickets(seasonTicket)
    user.save(flush: true, failOnError: true)

    expect: "we can find one season ticket"
    SeasonTicket.locateOrderedSeasonTicketsByUser(user).list().size() == 1
}

It looks as though the user field within the base class is not being recognised. What am I doing wrong please?


Solution

  • You have a naming conflict between your local parameter user and your class property 'user'.

    This part of your criteria

    user {
        idEq(user.id)
    }
    

    will try to call a method on your local parameter user which dosn't exist, instead of buidling your query using the user property of Ticket.

    Rename the parameter of your namedQuery locateOrderedSeasonTicketsByUser.