5. Object Relational Mapping (GORM)

Domain classes are core to any business application. They hold state about business processes and hopefully also implement behavior. They are linked together through relationships, either one-to-one or one-to-many.

GORM is Grails' object relational mapping (ORM) implementation. Under the hood it uses Hibernate 3 (an extremely popular and flexible open source ORM solution) but because of the dynamic nature of Groovy, the fact that it supports both static and dynamic typing, and the convention of Grails there is less configuration involved in creating Grails domain classes.

You can also write Grails domain classes in Java. See the section on Hibernate Integration for how to write Grails domain classes in Java but still use dynamic persistent methods. Below is a preview of GORM in action:

def book = Book.findByTitle("Groovy in Action")

book .addToAuthors(name:"Dierk Koenig") .addToAuthors(name:"Guillaume LaForge") .save()

5.1 Quick Start Guide

A domain class can be created with the create-domain-class command:

grails create-domain-class Person

This will create a class at the location grails-app/domain/Person.groovy such as the one below:

class Person {	
}

If you have the dbCreate property set to "update", "create" or "create-drop" on your DataSource, Grails will automatically generated/modify the database tables for you.

You can customize the class by adding properties:

class Person {	
	String name
	Integer age
	Date lastVisit
}

Once you have a domain class try and manipulate it via the shell or console by typing:

grails console

This loads an interactive GUI where you can type Groovy commands.

5.1.1 Basic CRUD

Try performing some basic CRUD (Create/Read/Update/Delete) operations.

Create

To create a domain class use the Groovy new operator, set its properties and call save:

def p = new Person(name:"Fred", age:40, lastVisit:new Date())
p.save()

The save method will persist your class to the database using the underlying Hibernate ORM layer.

Read

Grails transparently adds an implicit id property to your domain class which you can use for retrieval:

def p = Person.get(1)
assert 1 == p.id

This uses the get method that expects a database identifier to read the Person object back from the db. You can also load an object in a read-only state by using the read method:

def p = Person.read(1)

In this case the underlying Hibernate engine will not do any dirty checking and the object will not be persisted. Note that if you explicitly call the save method then the object is placed back into a read-write state.

Update

To update an instance, set some properties and then simply call save again:

def p = Person.get(1)
p.name = "Bob"
p.save()

Delete

To delete an instance use the delete method:

def p = Person.get(1)
p.delete()

5.2 Domain Modelling in GORM

When building Grails applications you have to consider the problem domain you are trying to solve. For example if you were building an Amazon bookstore you would be thinking about books, authors, customers and publishers to name a few.

These are modeled in GORM as Groovy classes so a Book class may have a title, a release date, an ISBN number and so on. The next few sections show how to model the domain in GORM.

To create a domain class you can run the create-domain-class target as follows:

grails create-domain-class Book

The result will be a class at grails-app/domain/Book.groovy:

class Book {	
}

If you wish to use packages you can move the Book.groovy class into a sub directory under the domain directory and add the appropriate package declaration as per Groovy (and Java's) packaging rules.

The above class will map automatically to a table in the database called book (the same name as the class). This behaviour is customizable through the ORM Domain Specific Language

Now that you have a domain class you can define its properties as Java types. For example:

class Book {
	String title
	Date releaseDate
	String ISBN
}

Each property is mapped to a column in the database, where the convention for column names is all lower case separated by underscores. For example releaseDate maps onto a column release_date. The SQL types are auto-detected from the Java types, but can be customized via Constraints or the ORM DSL.

5.2.1 Association in GORM

Relationships define how domain classes interact with each other. Unless specified explicitly at both ends, a relationship exists only in the direction it is defined.

5.2.1.1 One-to-one

A one-to-one relationship is the simplest kind, and is defined trivially using a property of the type of another domain class. Consider this example:

Example A

class Face {
    Nose nose
}
class Nose {	
}

In this case we have unidirectional one-to-one relationship from Face to Nose. To make this relationship bidirectional define the other side as follows:

Example B

class Face {
    Nose nose
}
class Nose {	
	Face face
}

This is bidirectional relationship. However, in this case no updates are cascading from either side of the relationship.

Consider this variation:

Example C

class Face {
    Nose nose
}
class Nose {	
	static belongsTo = [face:Face]
}

In this case we use the belongsTo setting to say that Nose "belongs to" Face. The result of this is that we can create a Face and save it and the database updates/inserts will be cascaded down to Nose:

new Face(nose:new Nose()).save()

The example above will save both face and nose. Note that the inverse is not true and will result in an error due to a transient Face:

new Nose(face:new Face()).save() // will cause an error

Another important implication of belongsTo is that if you delete a Face instance the Nose will be deleted too:

def f = Face.get(1)
f.delete() // both Face and Nose deleted

Without belongsTo deletes would not be cascading and you would get a foreign key constraint error unless you explicitly deleted the Nose:

// error here without belongsTo
def f = Face.get(1)
f.delete()

// no error as we explicitly delete both def f = Face.get(1) f.nose.delete() f.delete()

You could keep the previous relationship as unidirectional and allow saves/updates to cascade down by doing the following:

class Face {
    Nose nose
}
class Nose {	
	static belongsTo = Face
}

Note in this case because we are not using the map syntax in the belongsTo declaration and explicitly naming the association. Grails will assume it is unidirectional. The diagram below summarizes the 3 examples:

5.2.1.2 One-to-many

A one-to-many relationship is when one class, example Author, has many instances of a another class, example Book. With Grails you define such a relationship with the hasMany setting:

class Author {
    static hasMany = [ books : Book ]

String name } class Book { String title }

In this case we have a unidirectional one-to-many. Grails will, by default, map this kind of relationship with a join table.

The ORM DSL allows mapping unidirectional relationships using a foreign key association instead

Grails will automatically inject a property of type java.util.Set into the domain class based on the hasMany setting. This can be used to iterate over the collection:

def a = Author.get(1)

a.books.each { println it.title }

The default fetch strategy used by Grails is "lazy", which means that the collection will be lazily initialized. This can lead to the n+1 problem if you are not careful.

If you need "eager" fetching you can use the ORM DSL or specify eager fetching as part of a query

The default cascading behaviour is to cascade saves and updates, but not deletes unless a belongsTo is also specified:

class Author {
    static hasMany = [ books : Book ]

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

If you have two properties of the same type on the many side of a one-to-many you have to use mappedBy to specify which the collection is mapped:

class Airport {
	static hasMany = [flights:Flight]
	static mappedBy = [flights:"departureAirport"]
}
class Flight {
	Airport departureAirport
	Airport destinationAirport
}

This is also true if you have multiple collections that map to different properties on the many side:

class Airport {
	static hasMany = [outboundFlights:Flight, inboundFlights:Flight]
	static mappedBy = [outboundFlights:"departureAirport", inboundFlights:"destinationAirport"]
}
class Flight {
	Airport departureAirport
	Airport destinationAirport
}

5.2.1.3 Many-to-many

Grails supports many-to-many relationships by defining a hasMany on both sides of the relationship and having a belongsTo on the side that owns the relationship:

class Book {
   static belongsTo = Author
   static hasMany = [authors:Author]
   String title
}
class Author {
   static hasMany = [books:Book]
   String name
}

Grails maps a many-to-many using a join table at the database level. The owning side of the relationship, in this case Author, takes responsibility for persisting the relationship and is the only side that can cascade saves across.

For example this will work and cascade saves:

new Author(name:"Stephen King")
		.addToBooks(new Book(title:"The Stand"))
		.addToBooks(new Book(title:"The Shining"))		
		.save()

However the below will only save the Book and not the authors!

new Book(name:"Groovy in Action")
		.addToAuthors(new Author(name:"Dierk Koenig"))
		.addToAuthors(new Author(name:"Guillaume Laforge"))		
		.save()

This is the expected behaviour as, just like Hibernate, only one side of a many-to-many can take responsibility for managing the relationship.

Grails' Scaffolding feature does not currently support many-to-many relationship and hence you must write the code to manage the relationship yourself

5.2.1.4 Basic Collection Types

As well as associations between different domain classes, GORM also supports mapping of basic collection types. For example, the following class creates a nicknames association that is a Set of String instances:

class Person {
    static hasMany = [nicknames:String]
}

GORM will map an association like the above using a join table. You can alter various aspects of how the join table is mapped using the joinTable argument:

class Person {
    static hasMany = [nicknames:String]

static mapping = { hasMany joinTable:[name:'bunch_o_nicknames', key:'person_id', column:'nickname', type:"text"] } }

The example above will map to a table that looks like the following:

bunch_o_nicknames Table

---------------------------------------------
| person_id         |     nickname          |
---------------------------------------------
|   1               |      Fred             |
---------------------------------------------

5.2.2 Composition in GORM

As well as association, Grails supports the notion of composition. In this case instead of mapping classes onto separate tables a class can be "embedded" within the current table. For example:

class Person {
	Address homeAddress
	Address workAddress
	static embedded = ['homeAddress', 'workAddress']
}
class Address {
	String number
	String code
}

The resulting mapping would looking like this:

If you define the Address class in a separate Groovy file in the grails-app/domain directory you will also get an address table. If you don't want this to happen use Groovy's ability to define multiple classes per file and include the Address class below the Person class in the grails-app/domain/Person.groovy file

5.2.3 Inheritance in GORM

GORM supports inheritance both from abstract base classes and concrete persistent GORM entities. For example:

class Content {
     String author
}
class BlogEntry extends Content {
    URL url
}
class Book extends Content {
    String ISBN
}
class PodCast extends Content {
    byte[] audioStream
}

In the above example we have a parent Content class and then various child classes with more specific behaviour.

Considerations

At the database level Grails by default uses table-per-hierarchy mapping with a discriminator column called class so the parent class (Content) and its sub classes (BlogEntry, Book etc.), share the same table.

Table-per-hierarchy mapping has a down side in that you cannot have non-nullable properties with inheritance mapping. An alternative is to use table-per-subclass which can be enabled via the ORM DSL

However, excessive use of inheritance and table-per-subclass can result in poor query performance due to the excessive use of join queries. In general our advice is if you're going to use inheritance, don't abuse it and don't make your inheritance hierarchy too deep.

Polymorphic Queries

The upshot of inheritance is that you get the ability to polymorphically query. For example using the list method on the Content super class will return all sub classes of Content:

def content = Content.list() // list all blog entries, books and pod casts
content = Content.findAllByAuthor('Joe Bloggs') // find all by author

def podCasts = PodCast.list() // list only pod casts

5.2.4 Sets, Lists and Maps

Sets of objects

By default when you define a relationship with GORM it is a java.util.Set which is an unordered collection that cannot contain duplicates. In other words when you have:

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

The books property that GORM injects is a java.util.Set. The problem with this is there is no ordering when accessing the collection, which may not be what you want. To get custom ordering you can say that the set is a SortedSet:

class Author {
   SortedSet books
   static hasMany = [books:Book]
}

In this case a java.util.SortedSet implementation is used which means you have to implement java.lang.Comparable in your Book class:

class Book implements Comparable {
   String title
   Date releaseDate = new Date()

int compareTo(obj) { releaseDate.compareTo(obj.releaseDate) } }

The result of the above class is that the Book instances in the books collections of the Author class will be ordered by their release date.

Lists of objects

If you simply want to be able to keep objects in the order which they were added and to be able to reference them by index like an array you can define your collection type as a List:

class Author {
   List books
   static hasMany = [books:Book]
}

In this case when you add new elements to the books collection the order is retained in a sequential list indexed from 0 so you can do:

author.books[0] // get the first book

The way this works at the database level is Hibernate creates a books_idx column where it saves the index of the elements in the collection in order to retain this order at the db level.

When using a List, elements must be added to the collection before being saved, otherwise Hibernate will throw an exception (org.hibernate.HibernateException: null index column for collection):

// This won't work!
def book = new Book(title: 'The Shining')
book.save()
author.addToBooks(book)

// Do it this way instead. def book = new Book(title: 'Misery') author.addToBooks(book) author.save()

Maps of Objects

If you want a simple map of string/value pairs GORM can map this with the following:

class Author {
   Map books // map of ISBN:book names
}

def a = new Author() a.books = ["1590597583":"Grails Book"] a.save()

In this case the key and value of the map MUST be strings.

If you want a Map of objects then you can do this:

class Book {
  Map authors
  static hasMany = [authors:Author]
}

def a = new Author(name:"Stephen King")

def book = new Book() book.authors = [stephen:a] book.save()

The static hasMany property defines the type of the elements within the Map. The keys for the map must be strings.

A Note on Collection Types and Performance

The Java Set type is a collection that doesn't allow duplicates. In order to ensure uniqueness when adding an entry to a Set association Hibernate has to load the entire associations from the database. If you have a large numbers of entries in the association this can be costly in terms of performance.

The same behavior is required for List types, since Hibernate needs to load the entire association in-order to maintain order. Therefore it is recommended that if you anticipate a large numbers of records in the association that you make the association bidirectional so that the link can be created on the inverse side. For example consider the following code:

def book = new Book(title:"New Grails Book")
def author = Author.get(1)
book.author = author
book.save()

In this example the association link is being created by the child (Book) and hence it is not necessary to manipulate the collection directly resulting in fewer queries and more efficient code. Given an Author with a large number of associated Book instances if you were to write code like the following you would see an impact on performance:

def book = new Book(title:"New Grails Book")
def author = Author.get(1)
author.addToBooks(book)
author.save()

5.3 Persistence Basics

A key thing to remember about Grails is that under the surface Grails is using Hibernate for persistence. If you are coming from a background of using ActiveRecord or iBatis Hibernate's "session" model may feel a little strange.

Essentially, Grails automatically binds a Hibernate session to the currently executing request. This allows you to use the save and delete methods as well as other GORM methods transparently.

5.3.1 Saving and Updating

An example of using the save method can be seen below:

def p = Person.get(1)
p.save()

A major difference with Hibernate is when you call save it does not necessarily perform any SQL operations at that point. Hibernate typically batches up SQL statements and executes them at the end. This is typically done for you automatically by Grails, which manages your Hibernate session.

There are occasions, however, when you may want to control when those statements are executed or, in Hibernate terminology, when the session is "flushed". To do so you can use the flush argument to the save method:

def p = Person.get(1)
p.save(flush:true)

Note that in this case all pending SQL statements including previous saves will be synchronized with the db. This also allows you to catch any exceptions thrown, which is typically useful in highly concurrent scenarios involving optimistic locking:

def p = Person.get(1)
try {
	p.save(flush:true)
}
catch(Exception e) {
	// deal with exception
}

5.3.2 Deleting Objects

An example of the delete method can be seen below:

def p = Person.get(1)
p.delete()

By default Grails will use transactional write behind to perform the delete, if you want to perform the delete in place then you can use the flush argument:

def p = Person.get(1)
p.delete(flush:true)

Using the flush argument will also allow you to catch any errors that may potentially occur during a delete. A common error that may occur is if you violate a database constraint, although this is normally down to a programming or schema error. The following example shows how to catch a DataIntegrityViolationException that is thrown when you violate the database constraints:

def p = Person.get(1)

try { p.delete(flush:true) } catch(org.springframework.dao.DataIntegrityViolationException e) { flash.message = "Could not delete person ${p.name}" redirect(action:"show", id:p.id) }

Note that Grails does not supply a deleteAll method as deleting data is discouraged and can often be avoided through boolean flags/logic.

If you really need to batch delete data you can use the executeUpdate method to do batch DML statements:

Customer.executeUpdate("delete Customer c where c.name = :oldName", [oldName:"Fred"])

5.3.3 Understanding Cascading Updates and Deletes

It is critical that you understand how cascading updates and deletes work when using GORM. The key part to remember is the belongsTo setting which controls which class "owns" a relationship.

Whether it is a one-to-one, one-to-many or many-to-many if you define belongsTo updates and deletes will cascade from the owning class to its possessions (the other side of the relationship).

If you do not define belongsTo then no cascades will happen and you will have to manually save each object.

Here is an example:

class Airport {
	String name
	static hasMany = [flights:Flight]
}
class Flight {
	String number
	static belongsTo = [airport:Airport]
}

If I now create an Airport and add some Flights to it I can save the Airport and have the updates cascaded down to each flight, hence saving the whole object graph:

new Airport(name:"Gatwick")
	 .addToFlights(new Flight(number:"BA3430"))
	 .addToFlights(new Flight(number:"EZ0938"))
	 .save()

Conversely if I later delete the Airport all Flights associated with it will also be deleted:

def airport = Airport.findByName("Gatwick")
airport.delete()

However, if I were to remove belongsTo then the above cascading deletion code would not work. To understand this better take a look at the summaries below that describe the default behaviour of GORM with regards to specific associations.

Bidirectional one-to-many with belongsTo

class A { static hasMany = [bees:B] }
class B { static belongsTo = [a:A] }

In the case of a bidirectional one-to-many where the many side defines a belongsTo then the cascade strategy is set to "ALL" for the one side and "NONE" for the many side.

Unidirectional one-to-many

class A { static hasMany = [bees:B] }
class B {  }

In the case of a unidirectional one-to-many where the many side defines no belongsTo then the cascade strategy is set to "SAVE-UPDATE".

Bidirectional one-to-many no belongsTo

class A { static hasMany = [bees:B] }
class B { A a }

In the case of a bidirectional one-to-many where the many side does not define a belongsTo then the cascade strategy is set to "SAVE-UPDATE" for the one side and "NONE" for the many side.

Unidirectional One-to-one with belongsTo

class A {  }
class B { static belongsTo = [a:A] }

In the case of a unidirectional one-to-one association that defines a belongsTo then the cascade strategy is set to "ALL" for the owning side of the relationship (A->B) and "NONE" from the side that defines the belongsTo (B->A)

Note that if you need further control over cascading behaviour, you can use the ORM DSL.

5.3.4 Eager and Lazy Fetching

Associations in GORM are by default lazy. This is best explained by example:

class Airport {
	String name
	static hasMany = [flights:Flight]
}
class Flight {
	String number
	static belongsTo = [airport:Airport]
}

Given the above domain classes and the following code:

def airport = Airport.findByName("Gatwick")
airport.flights.each {
	println it.name
}

GORM will execute a single SQL query to fetch the Airport instance and then 1 extra query for each iteration over the flights association. In other words you get N+1 queries.

This can sometimes be optimal depending on the frequency of use of the association as you may have logic that dictates the associations is only accessed on certain occasions.

Configuring Eager Fetching

An alternative is to use eager fetching which can specified as follows:

class Airport {
	String name
	static hasMany = [flights:Flight]
	static mapping = {
		flight fetch:"join"
	}
}

In this case the association will be Airport instance and the flights association will be loaded all at once (depending on the mapping). This has the benefit of requiring fewer queries, however should be used carefully as you could load your entire database into memory with too many eager associations.

Associations can also be declared non-lazy using the ORM DSL

Using Batch Fetching

Although eager fetching is appropriate for some cases, it is not always desirable. If you made everything eager you could quite possibly load your entire database into memory resulting in performance and memory problems. An alternative to eager fetching is to use batch fetching. Essentially, you can configure Hibernate to lazily fetch results in "batches". For example:

class Airport {
	String name
	static hasMany = [flights:Flight]
	static mapping = {
		flight batchSize:10
	}
}

In this case, due to the batchSize argument, when you iterate over the flights association, Hibernate will fetch results in batches of 10. For example if you had an Airport that had 30 flights, if you didn't configure batch fetching you would get 1 query to fetch the Airport and then 30 queries to fetch each flight. With batch fetching you get 1 query to fetch the Airport and 3 queries to fetch each Flight in batches of 10. In other words, batch fetching is an optimization of the lazy fetching strategy. Batch fetching can also be configured at the class level as follows:

class Flight {
	…
	static mapping = {
		batchSize 10
	}
}

5.3.5 Pessimistic and Optimistic Locking

Optimistic Locking

By default GORM classes are configured for optimistic locking. Optimistic locking essentially is a feature of Hibernate which involves storing a version number in a special version column in the database.

The version column gets read into a version property that contains the current versioned state of persistent instance which you can access:

def airport = Airport.get(10)

println airport.version

When you perform updates Hibernate will automatically check the version property against the version column in the database and if they differ will throw a StaleObjectException and the transaction will be rolled back.

This is useful as it allows a certain level of atomicity without resorting to pessimistic locking that has an inherit performance penalty. The downside is that you have to deal with this exception if you have highly concurrent writes. This requires flushing the session:

def airport = Airport.get(10)

try { airport.name = "Heathrow" airport.save(flush:true) } catch(org.springframework.dao.OptimisticLockingFailureException e) { // deal with exception }

The way you deal with the exception depends on the application. You could attempt a programmatic merge of the data or go back to the user and ask them to resolve the conflict.

Alternatively, if it becomes a problem you can resort to pessimistic locking.

Pessimistic Locking

Pessimistic locking is equivalent to doing a SQL "SELECT * FOR UPDATE" statement and locking a row in the database. This has the implication that other read operations will be blocking until the lock is released.

In Grails pessimistic locking is performed on an existing instance via the lock method:

def airport = Airport.get(10)
airport.lock() // lock for update
airport.name = "Heathrow"
airport.save()

Grails will automatically deal with releasing the lock for you once the transaction has been committed. However, in the above case what we are doing is "upgrading" from a regular SELECT to a SELECT..FOR UPDATE and another thread could still have updated the record in between the call to get() and the call to lock().

To get around this problem you can use the static lock method that takes an id just like get:

def airport = Airport.lock(10) // lock for update
airport.name = "Heathrow"
airport.save()

In this case only SELECT..FOR UPDATE is issued.

Though Grails, through Hibernate, supports pessimistic locking, the embedded HSQLDB shipped with Grails which is used as the default in-memory database does not. If you need to test pessimistic locking you will need to do so against a database that does have support such as MySQL.

As well as the lock method you can also obtain a pessimistic locking using queries. For example using a dynamic finder:

def airport = Airport.findByName("Heathrow", [lock:true])

Or using criteria:

def airport = Airport.createCriteria().get {
	eq('name', 'Heathrow')
	lock true
}

5.4 Querying with GORM

GORM supports a number of powerful ways to query from dynamic finders, to criteria to Hibernate's object oriented query language HQL.

Groovy's ability to manipulate collections via GPath and methods like sort, findAll and so on combined with GORM results in a powerful combination.

However, let's start with the basics.

Listing instances

If you simply need to obtain all the instances of a given class you can use the list method:

def books = Book.list()

The list method supports arguments to perform pagination:

def books = Book.list(offset:10, max:20)

as well as sorting:

def books = Book.list(sort:"title", order:"asc")

Here, the sort argument is the name of the domain class property that you wish to sort on, and the order argument is either asc for ascending or desc for descending.

Retrieval by Database Identifier

The second basic form of retrieval is by database identifier using the get method:

def book = Book.get(23)

You can also obtain a list of instances for a set of identifiers using getAll:

def books = Book.getAll(23, 93, 81)

5.4.1 Dynamic Finders

GORM supports the concept of dynamic finders. A dynamic finder looks like a static method invocation, but the methods themselves don't actually exist in any form at the code level.

Instead, a method is auto-magically generated using code synthesis at runtime, based on the properties of a given class. Take for example the Book class:

class Book {
	String title
	Date releaseDate
	Author author
}                
class Author {
	String name
}

The Book class has properties such as title, releaseDate and author. These can be used by the findBy and findAllBy methods in the form of "method expressions":

def book = Book.findByTitle("The Stand")

book = Book.findByTitleLike("Harry Pot%")

book = Book.findByReleaseDateBetween( firstDate, secondDate )

book = Book.findByReleaseDateGreaterThan( someDate )

book = Book.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate )

Method Expressions

A method expression in GORM is made up of the prefix such as findBy followed by an expression that combines one or more properties. The basic form is:

Book.findBy([Property][Comparator][Boolean Operator])?[Property][Comparator]

The tokens marked with a '?' are optional. Each comparator changes the nature of the query. For example:

def book = Book.findByTitle("The Stand")

book = Book.findByTitleLike("Harry Pot%")

In the above example the first query is equivalent to equality whilst the latter, due to the Like comparator, is equivalent to a SQL like expression.

The possible comparators include:

Notice that the last 3 require different numbers of method arguments compared to the rest, as demonstrated in the following example:

def now = new Date()
def lastWeek = now - 7
def book = Book.findByReleaseDateBetween( lastWeek, now )

books = Book.findAllByReleaseDateIsNull() books = Book.findAllByReleaseDateIsNotNull()

Boolean logic (AND/OR)

Method expressions can also use a boolean operator to combine two criteria:

def books = 
    Book.findAllByTitleLikeAndReleaseDateGreaterThan("%Java%", new Date()-30)

In this case we're using And in the middle of the query to make sure both conditions are satisfied, but you could equally use Or:

def books = 
    Book.findAllByTitleLikeOrReleaseDateGreaterThan("%Java%", new Date()-30)

At the moment, you can only use dynamic finders with a maximum of two criteria, i.e. the method name can only have one boolean operator. If you need to use more, you should consider using either Criteria or the HQL.

Querying Associations

Associations can also be used within queries:

def author = Author.findByName("Stephen King")

def books = author ? Book.findAllByAuthor(author) : []

In this case if the Author instance is not null we use it in a query to obtain all the Book instances for the given Author.

Pagination & Sorting

The same pagination and sorting parameters available on the list method can also be used with dynamic finders by supplying a map as the final parameter:

def books = 
  Book.findAllByTitleLike("Harry Pot%", [max:3, 
                                         offset:2, 
                                         sort:"title",
                                         order:"desc"])

5.4.2 Criteria

Criteria is a type safe, advanced way to query that uses a Groovy builder to construct potentially complex queries. It is a much better alternative to using StringBuffer.

Criteria can be used either via the createCriteria or withCriteria methods. The builder uses Hibernate's Criteria API, the nodes on this builder map the static methods found in the Restrictions class of the Hibernate Criteria API. Example Usage:

def c = Account.createCriteria()
def results = c {
	like("holderFirstName", "Fred%")
	and {
		between("balance", 500, 1000)
		eq("branch", "London")
	}
	maxResults(10)
	order("holderLastName", "desc")
}

Conjunctions and Disjunctions

As demonstrated in the previous example you can group criteria in a logical AND using a and { } block:

and {
	between("balance", 500, 1000)
	eq("branch", "London")
}

This also works with logical OR:

or {
	between("balance", 500, 1000)
	eq("branch", "London")
}

And you can also negate using logical NOT:

not {
	between("balance", 500, 1000)
	eq("branch", "London")
}

Querying Associations

Associations can be queried by having a node that matches the property name. For example say the Account class had many Transaction objects:

class Account {
    …
    def hasMany = [transactions:Transaction]
    Set transactions
    …
}

We can query this association by using the property name transaction as a builder node:

def c = Account.createCriteria()
def now = new Date()
def results = c.list {
       transactions {
            between('date',now-10, now)
       }
}

The above code will find all the Account instances that have performed transactions within the last 10 days. You can also nest such association queries within logical blocks:

def c = Account.createCriteria()
def now = new Date()
def results = c.list {
     or {
        between('created',now-10,now)
        transactions {
             between('date',now-10, now)
        }
     }
}

Here we find all accounts that have either performed transactions in the last 10 days OR have been recently created in the last 10 days.

Querying with Projections

Projections may be used to customise the results. To use projections you need to define a "projections" node within the criteria builder tree. There are equivalent methods within the projections node to the methods found in the Hibernate Projections class:

def c = Account.createCriteria()

def numberOfBranches = c.get { projections { countDistinct('branch') } }

Using Scrollable Results

You can use Hibernate's ScrollableResults feature by calling the scroll method:

def results = crit.scroll {
      maxResults(10)
}
def f = results.first()
def l = results.last()
def n = results.next()
def p = results.previous()

def future = results.scroll(10) def accountNumber = results.getLong('number')

To quote the documentation of Hibernate ScrollableResults:

A result iterator that allows moving around within the results by arbitrary increments. The Query / ScrollableResults pattern is very similar to the JDBC PreparedStatement/ ResultSet pattern and the semantics of methods of this interface are similar to the similarly named methods on ResultSet.

Contrary to JDBC, columns of results are numbered from zero.

Setting properties in the Criteria instance

If a node within the builder tree doesn't match a particular criterion it will attempt to set a property on the Criteria object itself. Thus allowing full access to all the properties in this class. The below example calls setMaxResults and setFirstResult on the Criteria instance:

import org.hibernate.FetchMode as FM
	…
	def results = c.list {
		maxResults(10)
		firstResult(50)
		fetchMode("aRelationship", FM.EAGER)
	}

Querying with Eager Fetching

In the section on Eager and Lazy Fetching we discussed how to declaratively specify fetching to avoid the N+1 SELECT problem. However, this can also be achieved using a criteria query:

def criteria = Task.createCriteria()
def tasks = criteria.list{
     eq "assignee.id", task.assignee.id
     join 'assignee'
     join 'project'
     order 'priority', 'asc'
}

Notice the usage of the join method. This method indicates the criteria API that a JOIN query should be used to obtain the results.

Method Reference

If you invoke the builder with no method name such as:

c { … }

The build defaults to listing all the results and hence the above is equivalent to:

c.list { … }

MethodDescription
listThis is the default method. It returns all matching rows.
getReturns a unique result set, i.e. just one row. The criteria has to be formed that way, that it only queries one row. This method is not to be confused with a limit to just the first row.
scrollReturns a scrollable result set
listDistinctIf subqueries or associations are used, one may end up with the same row multiple times in the result set, this allows listing only distinct entities and is equivalent to DISTINCT_ROOT_ENTITY of the CriteriaSpecification class

5.4.3 Hibernate Query Language (HQL)

GORM classes also support Hibernate's query language HQL, a very complete reference for which can be found Chapter 14. HQL: The Hibernate Query Language of the Hibernate documentation.

GORM provides a number of methods that work with HQL including find, findAll and executeQuery. An example of a query can be seen below:

def results =
      Book.findAll("from Book as b where b.title like 'Lord of the%'")

Positional and Named Parameters

In this case the value passed to the query is hard coded, however you can equally use positional parameters:

def results =
      Book.findAll("from Book as b where b.title like ?", ["The Shi%"])

Or even named parameters:

def results =
      Book.findAll("from Book as b where b.title like :search or b.author like :search", [search:"The Shi%"])

Multiline Queries

If you need to separate the query across multiple lines you can use a line continuation character:

def results = Book.findAll("\
from Book as b, \
     Author as a \
where b.author = a and a.surname = ?", ['Smith'])

Groovy multiline strings will NOT work with HQL queries

Pagination and Sorting

You can also perform pagination and sorting whilst using HQL queries. To do so simply specify the pagination options as a map at the end of the method call and include an "ORDER BY" clause in the HQL:

def results =
      Book.findAll("from Book as b where b.title like 'Lord of the%' order by b.title asc",
                   [max:10, offset:20])

5.5 Advanced GORM Features

The following sections cover more advanced usages of GORM including caching, custom mapping and events.

5.5.1 Events and Auto Timestamping

GORM supports the registration of events as closures that get fired when certain events occurs such as deletes, inserts and updates. The following is a list of supported events:

To add an event simply register the relevant closure with your domain class.

Event types

The beforeInsert event

Fired before an object is saved to the db

class Person {
   Date dateCreated

def beforeInsert = { dateCreated = new Date() } }

The beforeUpdate event

Fired before an existing object is updated

class Person {
   Date dateCreated
   Date lastUpdated

def beforeInsert = { dateCreated = new Date() } def beforeUpdate = { lastUpdated = new Date() } }

The beforeDelete event

Fired before an object is deleted.

class Person {
   String name
   Date dateCreated
   Date lastUpdated

def beforeDelete = { new ActivityTrace(eventName:"Person Deleted",data:name).save() } }

The onLoad event

Fired when an object is loaded from the db:

class Person {
   String name
   Date dateCreated
   Date lastUpdated

def onLoad = { name = "I'm loaded" } }

Automatic timestamping

The examples above demonstrated using events to update a lastUpdated and dateCreated property to keep track of updates to objects. However, this is actually not necessary. By merely defining a lastUpdated and dateCreated property these will be automatically updated for you by GORM.

If this is not the behaviour you want you can disable this feature with:

class Person {
   Date dateCreated
   Date lastUpdated
   static mapping = {
      autoTimestamp false
   }
}

5.5.2 Custom ORM Mapping

Grails domain classes can be mapped onto many legacy schemas via an Object Relational Mapping Domain Specify Language. The following sections takes you through what is possible with the ORM DSL.

None if this is necessary if you are happy to stick to the conventions defined by GORM for table, column names and so on. You only needs this functionality if you need to in anyway tailor the way GORM maps onto legacy schemas or performs caching

Custom mappings are defined using a a static mapping block defined within your domain class:

class Person {
  ..
  static mapping = {

} }

5.5.2.1 Table and Column Names

Table names

The database table name which the class maps to can be customized using a call to table:

class Person {
  ..
  static mapping = {
      table 'people'
  }
}

In this case the class would be mapped to a table called people instead of the default name of person.

Column names

It is also possible to customize the mapping for individual columns onto the database. For example if its the name you want to change you can do:

class Person {
  String firstName
  static mapping = {
      table 'people'
      firstName column:'First_Name'
  }
}

In this case we define method calls that match each property name (in this case firstName). We then use the named parameter column, to specify the column name to map onto.

Column type

GORM supports configuration of Hibernate types via the DSL using the type attribute. This includes specifing user types that subclass the Hibernate org.hibernate.usertype.UserType class, which allows complete customization of how a type is persisted. As an example if you had a PostCodeType you could use it as follows:

class Address {
   String number
   String postCode
   static mapping = {
      postCode type:PostCodeType
   }
}

Alternatively if you just wanted to map it to one of Hibernate's basic types other than the default chosen by Grails you could use:

class Address {
   String number
   String postCode
   static mapping = {
      postCode type:'text'
   }
}

This would make the postCode column map to the SQL TEXT or CLOB type depending on which database is being used.

See the Hibernate documentation regarding Basic Types for further information.

One-to-One Mapping

In the case of associations it is also possible to change the foreign keys used to map associations. In the case of a one-to-one association this is exactly the same as any regular column. For example consider the below:

class Person {
  String firstName
  Address address
  static mapping = {
      table 'people'
      firstName column:'First_Name'
	  address column:'Person_Adress_Id'
  }
}

By default the address association would map to a foreign key column called address_id. By using the above mapping we have changed the name of the foreign key column to Person_Adress_Id.

One-to-Many Mapping

With a bidirectional one-to-many you can change the foreign key column used simple by changing the column name on the many side of the association as per the example in the previous section on one-to-one associations. However, with unidirectional association the foreign key needs to be specified on the association itself. For example given a unidirectional one-to-many relationship between Person and Address the following code will change the foreign key in the address table:

class Person {
  String firstName
  static hasMany = [addresses:Address]
  static mapping = {
      table 'people'
      firstName column:'First_Name'
	  addresses column:'Person_Address_Id'
  }
}

If you don't want the column to be in the address table, but instead some intermediate join table you can use the joinTable parameter:

class Person {
  String firstName
  static hasMany = [addresses:Address]
  static mapping = {
      table 'people'
      firstName column:'First_Name'
      addresses joinTable:[name:'Person_Addresses', key:'Person_Id', column:'Address_Id']
  }
}

Many-to-Many Mapping

Grails, by default maps a many-to-many association using a join table. For example consider the below many-to-many association:

class Group {
	…
	static hasMany = [people:Person]
}
class Person {
	…
	static belongsTo = Group
	static hasMany = [groups:Group]
}

In this case Grails will create a join table called group_person containing foreign keys called person_id and group_id referencing the person and group tables. If you need to change the column names you can specify a column within the mappings for each class.

class Group {
   …
   static mapping = {
       people column:'Group_Person_Id'
   }	
}
class Person {
   …
   static mapping = {
       groups column:'Group_Group_Id'
   }	
}

You can also specify the name of the join table to use:

class Group {
   …
   static mapping = {
       people column:'Group_Person_Id',joinTable:'PERSON_GROUP_ASSOCIATIONS'
   }	
}
class Person {
   …
   static mapping = {
       groups column:'Group_Group_Id',joinTable:'PERSON_GROUP_ASSOCIATIONS'
   }	
}

5.5.2.2 Caching Strategy

Setting up caching

Hibernate features a second-level cache with a customizable cache provider. This needs to be configured in the grails-app/conf/DataSource.groovy file as follows:

hibernate {
    cache.use_second_level_cache=true
    cache.use_query_cache=true
    cache.provider_class='org.hibernate.cache.EhCacheProvider'
}

You can of course customize these settings how you desire, for example if you want to use a distributed caching mechanism.

For further reading on caching and in particular Hibernate's second-level cache, refer to the Hibernate documentation on the subject.

Caching instances

In your mapping block to enable caching with the default settings use a call to the cache method:

class Person {
  ..
  static mapping = {
      table 'people'
      cache true
  }
}

This will configure a 'read-write' cache that includes both lazy and non-lazy properties. If you need to customize this further you can do:

class Person {
  ..
  static mapping = {
      table 'people'
      cache usage:'read-only', include:'non-lazy'
  }
}

Caching associations

As well as the ability to use Hibernate's second level cache to cache instances you can also cache collections (associations) of objects. For example:

class Person {
  String firstName
  static hasMany = [addresses:Address]
  static mapping = {
      table 'people'
      version false
      addresses column:'Address', cache:true
  }
}
class Address {
   String number
   String postCode
}

This will enable a 'read-write' caching mechanism on the addresses collection. You can also use:

cache:'read-write' // or 'read-only' or 'transactional'

To further configure the cache usage.

Caching Queries

You can cache queries such as dynamic finders and criteria. To do so using a dynamic finder you can pass the cache argument:

def person = Person.findByFirstName("Fred", cache:true)

Note that in order for the results of the query to be cached, you still need to enable caching in your mapping as discussed in the previous section.

You can also cache criteria queries:

def people = Person.withCriteria {
	like('firstName', 'Fr%')
	cache true
}

Cache usages

Below is a description of the different cache settings and their usages:

5.5.2.3 Inheritance Strategies

By default GORM classes uses table-per-hierarchy inheritance mapping. This has the disadvantage that columns cannot have a NOT-NULL constraint applied to them at the db level. If you would prefer to use a table-per-subclass inheritance strategy you can do so as follows:

class Payment {
    Long id
    Long version
    Integer amount

static mapping = { tablePerHierarchy false } } class CreditCardPayment extends Payment { String cardNumber }

The mapping of the root Payment class specifies that it will not be using table-per-hierarchy mapping for all child classes.

5.5.2.4 Custom Database Identity

You can customize how GORM generates identifiers for the database using the DSL. By default GORM relies on the native database mechanism for generating ids. This is by far the best approach, but there are still many schemas that have different approaches to identity.

To deal with this Hibernate defines the concept of an id generator. You can customize the id generator and the column it maps to as follows:

class Person {
  ..
  static mapping = {
      table 'people'
      version false
      id generator:'hilo', params:[table:'hi_value',column:'next_value',max_lo:100]
  }
}

In this case we're using one of Hibernate's built in 'hilo' generators that uses a separate table to generate ids.

For more information on the different Hibernate generators refer to the Hibernate reference documentation

Note that if you want to merely customise the column that the id lives on you can do:

class Person {
  ..
  static mapping = {
      table 'people'
      version false
      id column:'person_id'
  }
}

5.5.2.5 Composite Primary Keys

GORM supports the concept of composite identifiers (identifiers composed from 2 or more properties). It is not an approach we recommend, but is available to you if you need it:

class Person {
  String firstName
  String lastName

static mapping = { id composite:['firstName', 'lastName'] } }

The above will create a composite id of the firstName and lastName properties of the Person class. When you later need to retrieve an instance by id you have to use a prototype of the object itself:

def p = Person.get(new Person(firstName:"Fred", lastName:"Flintstone"))
println p.firstName

5.5.2.6 Database Indices

To get the best performance out of your queries it is often necessary to tailor the table index definitions. How you tailor them is domain specific and a matter of monitoring usage patterns of your queries. With GORM's DSL you can specify which columns need to live in which indexes:

class Person {
  String firstName
  String address
  static mapping = {
      table 'people'
      version false
      id column:'person_id'
      firstName column:'First_Name', index:'Name_Idx'
      address column:'Address', index:'Name_Idx, Address_Index'
  }
}

5.5.2.7 Optimistic Locking and Versioning

As discussed in the section on Optimistic and Pessimistic Locking, by default GORM uses optimistic locking and automatically injects a version property into every class which is in turn mapped to a version column at the database level.

If you're mapping to a legacy schema this can be problematic, so you can disable this feature by doing the following:

class Person {
  ..
  static mapping = {
      table 'people'
      version false
  }
}

If you disable optimistic locking you are essentially on your own with regards to concurrent updates and are open to the risk of users losing (due to data overriding) data unless you use pessimistic locking

5.5.2.8 Eager and Lazy Fetching

Lazy Collections

As discussed in the section on Eager and Lazy fetching, by default GORM collections use lazy fetching and is is configurable through the fetchMode setting. However, if you prefer to group all your mappings together inside the mappings block you can also use the ORM DSL to configure fetching:

class Person {
  String firstName
  static hasMany = [addresses:Address]
  static mapping = {
      addresses lazy:false
  }
}
class Address {
  String street
  String postCode
}

Lazy Single-Ended Associations

In GORM, one-to-one and many-to-one associations are by default non-lazy. This can be problematic in cases when you are loading many entities which have an association to another entity as a new SELECT statement is executed for each loaded entity. You can make one-to-one and many-to-one associations lazy using the same technique as for lazy collections:

class Person {
	String firstName
	static belongsTo = [address:Address]
	static mapping = {
		address lazy:true // lazily fetch the address
	}
}
class Address {
	String street
	String postCode
}

Here we set the address property of the Person class to be lazily loaded.

5.5.2.9 Custom Cascade Behaviour

As describes in the section on cascading updates, the primary mechanism to control the way updates and deletes are cascading from one association to another is the belongsTo static property.

However, the ORM DSL gives you complete access to Hibernate's transitive persistence capabilities via the cascade attribute.

Valid settings for the cascade attribute include:

It is advisable to read the section in the Hibernate documentation on transitive persistence to obtain a better understanding of the different cascade styles and recommendation for their usage

To specific the cascade attribute simply define one or many (comma-separated) of the aforementioned settings as its value:

class Person {
  String firstName
  static hasMany = [addresses:Address]
  static mapping = {
      addresses cascade:"all,delete-orphan"
  }
}
class Address {
  String street
  String postCode
}

5.5.2.10 Custom Hibernate Types

You saw in an earlier section that you can use composition (via the embedded property) to break a table into multiple objects. You can achieve a similar effect via Hibernate's custom user types. These are not domain classes themselves, but plain Java or Groovy classes with associated. Each of these types also has a corresponding "meta-type" class that implements org.hibernate.usertype.UserType.

The Hibernate reference manual has some information on custom types, but here we will focus on how to map them in Grails. Let's start by taking a look at a simple domain class that uses an old-fashioned (pre-Java 1.5) type-safe enum class:

class Book {
  String title
  String author
  Rating rating

static mapping = { rating type: RatingUserType } }

All we have done is declare the rating field the enum type and set the property's type in the custom mapping to the corresponding UserType implementation. That's all you have to do to start using your custom type. If you want, you can also use the other column settings such as "column" to change the column name and "index" to add it to an index.

Custom types aren't limited to just a single column - they can be mapped to as many columns as you want. In such cases you need to explicitly define in the mapping what columns to use, since Hibernate can only use the property name for a single column. Fortunately, Grails allows you to map multiple columns to a property using this syntax:

class Book {
  String title
  Name author
  Rating rating

static mapping = { name type: NameUserType, { column name: "first_name" column name: "last_name" } rating type: RatingUserType } }

The above example will create "first_name" and "last_name" columns for the author property. You'll be pleased to know that you can also use some of the normal column/property mapping attributes in the column definitions. For example:

column name: "first_name", index: "my_idx", unique: true

The column definitions do not support the following attributes: type, cascade, lazy, cache, and joinTable.

One thing to bear in mind with custom types is that they define the SQL types for the corresponding database columns. That helps take the burden of configuring them yourself, but what happens if you have a legacy database that uses a different SQL type for one of the columns? In that case, you need to override column's SQL type using the sqlType attribute:

class Book {
  String title
  Name author
  Rating rating

static mapping = { name type: NameUserType, { column name: "first_name", sqlType: "text" column name: "last_name", sqlType: "text" } rating type: RatingUserType, sqlType: "text" } }

Mind you, the SQL type you specify needs to still work with the custom type. So overriding a default of "varchar" with "text" is fine, but overriding "text" with "yes_no" isn't going to work.

5.5.3 Default Sort Order

You can sort objects using queries arguments such as those found in the list method:

def airports = Airport.list(sort:'name')

However, you can also declare the sort order declaratively:

class Airport {
	…
	static mapping = {
		sort "name"
	}
}

You can also configure the sort order if necessary:

class Airport {
	…
	static mapping = {
		sort name:"desc"
	}
}

Alternatively, you can configure sort order at the association level:

class Airport {
	…
	static hasMany = [flights:Flight]
	static mapping = {
		flights sort:'number'
	}
}

5.6 Programmatic Transactions

Grails is built on Spring and hence uses Spring's Transaction abstraction for dealing with programmatic transactions. However, GORM classes have been enhanced to make this more trivial through the withTransaction method which accepts a block the first argument to which is the Spring TransactionStatus object.

A typical usage scenario is as follows:

def transferFunds = {
	Account.withTransaction { status ->
		def source = Account.get(params.from)
		def dest = Account.get(params.to)

def amount = params.amount.toInteger() if(source.active) { source.balance -= amount if(dest.active) { dest.amount += amount } else { status.setRollbackOnly() } }

}

}

In this example we rollback the transactions if the destination account is not active and if any exception are thrown during the process the transaction will automatically be rolled back.

You can also use "save points" to rollback a transaction to a particular point in time if you don't want to rollback the entire transaction. This can be achieved through the use of Spring's SavePointManager interface.

The withTransaction method deals with the begin/commit/rollback logic for you within the scope of the block.

5.7 GORM and Constraints

Although constraints are covered in the Validation section, it is important to mention them here as some of the constraints can affect the way in which the database schema is generated.

Where feasible, Grails uses a domain class's constraints to influence the database columns generated for the corresponding domain class properties.

Consider the following example. Suppose we have a domain model with the following property.

String name
String description

By default, in MySQL, Grails would define these columns as...

column name | data type 
 description | varchar(255)

But perhaps the business rules for this domain class state that a description can be up to 1000 characters in length. If that were the case, we'd likely define the column as follows if we were creating the table via an SQL script.

column name | data type 
 description | TEXT

Chances are we'd also want to have some application-based validation to make sure we don't exceed that 1000 character limit before we persist any records. In Grails, we achieve this validation via constraints. We'd add the following constraint declaration to the domain class.

static constraints = {
        description(maxSize:1000)
}

This constraint would provide both the application-based validation we want and it would also cause the schema to be generated as shown above. Below is a description of the other constraints that influence schema generation.

Constraints Affecting String Properties

If either the maxSize or the size constraint is defined, Grails sets the maximum column length based on the constraint value.

In general, it's not advisable to use both constraints on the same domain class property. However, if both the maxSize constraint and the size constraint are defined, then Grails sets the column length to the minimum of the maxSize constraint and the upper bound of the size constraint. (Grails uses the minimum of the two, because any length that exceeds that minimum will result in a validation error.)

If the inList constraint is defined (and the maxSize and the size constraints are not defined), then Grails sets the maximum column length based on the length of the longest string in the list of valid values. For example, given a list including values "Java", "Groovy", and "C++", Grails would set the column length to 6 (i.e., the number of characters in the string "Groovy").

Constraints Affecting Numeric Properties

If the max constraint, the min constraint, or the range constraint is defined, Grails attempts to set the column precision based on the constraint value. (The success of this attempted influence is largely dependent on how Hibernate interacts with the underlying DBMS.)

In general, it's not advisable to combine the pair min/max and range constraints together on the same domain class property. However, if both of these constraints is defined, then Grails uses the minimum precision value from the constraints. (Grails uses the minimum of the two, because any length that exceeds that minimum precision will result in a validation error.)

If the scale constraint is defined, then Grails attempts to set the column scale based on the constraint value. This rule only applies to floating point numbers (i.e., java.lang.Float, java.Lang.Double, java.lang.BigDecimal, or subclasses of java.lang.BigDecimal). (The success of this attempted influence is largely dependent on how Hibernate interacts with the underlying DBMS.)

The constraints define the minimum/maximum numeric values, and Grails derives the maximum number of digits for use in the precision. Keep in mind that specifying only one of min/max constraints will not affect schema generation (since there could be large negative value of property with max:100, for example), unless specified constraint value requires more digits than default Hibernate column precision is (19 at the moment). For example...

someFloatValue(max:1000000, scale:3)

would yield:

someFloatValue DECIMAL(19, 3) // precision is default

but

someFloatValue(max:12345678901234567890, scale:5)

would yield:

someFloatValue DECIMAL(25, 5) // precision = digits in max + scale

and

someFloatValue(max:100, min:-100000)

would yield:

someFloatValue DECIMAL(8, 2) // precision = digits in min + default scale