Home > English, Programming > Grails: Separating the database access from the domain classes

Grails: Separating the database access from the domain classes

Some days ago I started working on my second project involving Groovy & Grails.
Grails is my first contact with server side development with dynamic languages, and, despite some small problems (mostly due to the fact that the framework is still not so mature compared to others out there), I really, really enjoy it.

One of the things that I like is how using Groovy’s dynamic features the framework injects database access technicalities into our domain classes.
The domain is therefore smart enough to retrieve/update its relationships and even to find/update itself, all without the need to pass around repositories dependencies whatsoever, or to force the domain classes to extend any other classes.

But sometimes we need to write HQL (or criterias) ourselves, and then in our first project we ended up having some domain classes quite bloated with custom queries and a lot of other database related operations mixed with pure domain-specific logic operations.

Something like this:

  class Book {
    // properties, mappings, constraints
    // domain methods

    def findAllBooksFromTheSameAuthor() {
      return findAll("some HQL")
    }

    def findSimilarPurchasedBooks() {
      return findAll("some HQL")
    }
  }

This code is just a silly example to illustrate the problem.
Of course we could have used Grails’ dynamic finders for those queries too, but we would be externalizing the internals of our domain class so we like this approach of adding custom query methods better.
One thing we didn’t like though, is that we had many methods like the ones above, mixed with the domain logic and properties.
So we decided to move these methods somewhere else and inject them into our domain classes, like Grails does with its dynamic generic finders.

A very nice way to do it seemed to be using Groovy’s Delegate annotation, having something similar to:

  class Book {
    @Delegate BookQueries bookQueries = new BookQueries(this)

    // properties
    // mappings, constraints, domain methods
  }

  class BookQueries {
    Book book

    BookQueries(Book book) {
      this.book = book
    }

    def findAllBooksFromTheSameAuthor() {
      return Book.findAll("some HQL")
    }

    def findSimilarPurchasedBooks() {
      return Book.findAll("some HQL")
    }
  }

We have to pass the book object to BookQueries because we are gonna need its properties to build our queries.
For instance, we need its author to find all books from the same author.
And using the delegate we can call methods from BookQueries with a Book object:

  book.findSimilarPurchasedBooks()

The only problem with this is that we also had some static methods to first retrieve our objects.
These are queries that are not related to any relationship or similarities between objects, so they are static methods in the Book class:

  static def findBestSellersInMonth() {
    findAll("some HQL")
  }

The problem is that static methods are not delegated.

In our project we decided to scrap the @Delegate for good, move all custom query methods to BookQueries, including the static ones, transform them into closures and inject them manually, one by one, into the Book class during the application BootStrap, using Groovy’s Expando metaclass.

But I didn’t really like this approach.
I think I’d rather keep the @Delegate, and then move the static methods to a BookRepository class:

  class BookRepository {
    def findBestSellersInMonth() {
      return Book.findAll("some HQL")
    }
  }

It might seem as a step backwards.. “why do you need repositories if you have your rich domain that can retrieve itself?”
But the static modifier already tells that these methods don’t belong to our domain *objects*.
They are there to initialize the objects, retrieve them from somewhere (the database).
And, well, isn’t this part of the definition of repositories? =P

Update — May 10th ———————————

Peter Ledbrook suggested using Grails’ named queries (see comments). It looks indeed very nice, but we really wanted to move our queries out of our domain class, to make it more readable and, well, prettier :D

With the named queries we could move a static block containing the static queries to the BooksQueries class and assign this static block to a static nameQueries block in the Book class, and this would import the static queries.

Today I was messing with this a bit more and I realized that I could just inject the static methods into my domain class from inside my delegate itself.
It’s so simple I don’t understand how come I didn’t think about that before :D
So, if you don’t like the repository approach, you can always have something like:

  class Book {
    @Delegate BookQueries bookQueries = new BookQueries(this)
    // all Book properties, constraints, domain methods, etc
  }

  class BookQueries {

    static {
      BookQueries.metaClass.methods.each {
        if (it.static) {
          Book.metaClass.static."$it.name" = owner.&"$it.name"
        }
      }
    }

    Book book

    BookQueries(Book book) {
      this.book = book
    }

    def findAllBooksFromTheSameAuthor() {
      return Book.findAll("some HQL")
    }

    static def findBestSellersInMonth() {
      return Book.findAll("some HQL")
    }
  }

About these ads
  1. Peter Ledbrook
    May 10, 2010 at 11:43

    An alternative approach is to use Grails’ named queries:

    http://grails.org/doc/latest/ref/Domain%20Classes/namedQueries.html

    Available since Grails 1.2.

    Peter

    • May 10, 2010 at 13:10

      Oh, right! I didn’t know about these named queries. Our previous project was all done with Grails 1.1, I guess that’s why. Thank you, Peter!

      So I am thinking mixing @Delegate and the named queries should do it in a much nicer way. Or can I use the named queries for the instance methods too? (Without having to pass the objects as parameters).

      I will update the post later adding the information about named queries.

      • May 10, 2010 at 14:45

        Actually, I just figured that we can use the delegate annotation and inject only the static methods manually.

        I think this is a pretty nice solution, I will update later the post adding it.

  1. September 24, 2010 at 05:18

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: