Search code examples
grailsgrails-orm

Grails count children of one to many within the domain class


I have a one-to-many relationship:

class Author {
    String name
    static hasMany = [books:Book]
    static constraints = {
    }
}

class Book {
    String name
    static belongsTo = [author:Author]
    static constraints = {
    }
}

I want to be able to count the number of books that belong to an author within the author class such that the resulting generated MySQL table would look like this:

id | version | name | bookcount
-- | ------- | ---- | ---------
 1 |       0 | foo  |        15
 2 |       0 | bar  |         3
 3 |       0 | baz  |         7

...where bookcount is a defined field in the author class:

class Author {
    String name
    int bookcount = ??
    static constraints = {
    }
}

EDIT 1: bookcount must be persisted in the database.


Solution

  • You can do the following using gorm events:

    class Author {
        String name
    
        Integer bookCount = 0
        static hasMany = [books:Book]
    
        Integer getBookCount () {
            books?.size () ?: 0
        }
    
        void beforeUpdate () {
            bookCount = getBookCount ()
        }
    
        static constraints = {
        }
    }
    

    The beforeUpdate method will be called before the object is updated in the database.

    The getBookCount() property getter makes sure we always get the correct value. If the author is not yet saved after adding more Books, bookCount would not be up to date until author is save()d.

    If we don't use bookCount from code we could inline it.

    def "explicitly persist book count" () {
        given:
        Author author = new Author(name:'author')
        author.save (failOnError: true)
    
        when:
        author.addToBooks (new Book(name:'book'))
        author.save (failOnError: true, flush: true)
    
        then:
        author.bookCount == 1
        author.@bookCount == 1
    }