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; one-to-one, one-to-many, or many-to-many.

GORM is Grails' object relational mapping (ORM) implementation. Under the hood it uses Hibernate 3 (a very popular and flexible open source ORM solution) and thanks to the dynamic nature of Groovy with its static and dynamic typing, along with the convention of Grails, there is far 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 domain classes in Java but still use dynamic persistent methods. Below is a preview of GORM in action:

Create

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 database.
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.

In addition, you can also load a proxy for an instance by using the load method:

def p = Person.load(1)

This incurs no database access until a method other than getId() is called. Hibernate then initializes the proxied instance, or
throws an exception if no record is found for the specified id.

Update

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

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

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-style 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.

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

package org.bookstore

class Book {
}

This 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:

package org.bookstore

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 with 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 Many-to-one and one-to-one

A many-to-one relationship is the simplest kind, and is defined with 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 a unidirectional many-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 {
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, attach a Nose instance to it and when we save or delete the Face instance, GORM will save or delete the Nose. In other words, saves and deletes will cascade from Face to the associated 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

Now if we delete the Face instance, the Nose will go too:

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

To make the relationship a true one-to-one, use the hasOne property on the owning side, e.g. Face:

Example C

class Face {
static hasOne = [nose:Nose]
}

class Nose {
Face face
}

Note that using this property puts the foreign key on the inverse table to the previous example, so in this case the foreign key column is stored in the nose table inside a column called face_id. Also, hasOne only works with bidirectional relationships.

Finally, it's a good idea to add a unique constraint on one side of the one-to-one relationship:

class Face {
static hasOne = [nose:Nose]

static constraints = {
nose unique: true
}
}

class Nose {
Face face
}

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.

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.

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:

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

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 subclasses (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 with the ORM DSL

However, excessive use of inheritance and table-per-subclass can result in poor query performance due to the use of outer 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 subclasses of Content:

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

Bags of Objects

If ordering and uniqueness aren't a concern (or if you manage these explicitly) then you can use the Hibernate Bag type to represent mapped collections.

The only change required for this is to define the collection type as a Collection:

class Author {

Collection books

static hasMany = [books: Book]
}

Since uniqueness and order aren't managed by Hibernate, adding to or removing from collections mapped as a Bag don't trigger a load of all existing instances from the database, so this approach will perform better and require less memory than using a Set or a List.

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 doesn't allow duplicates. 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 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:

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:

You could also model the collection as a Hibernate Bag as described above.

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/MyBatis, Hibernate's "session" model may feel a little strange.

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

Transactional Write-Behind

A useful feature of Hibernate over direct JDBC calls and even other frameworks is that when you call save or delete it does not necessarily perform any SQL operations at that point. Hibernate batches up SQL statements and executes them as late as possible, often at the end of the request when flushing and closing the session. This is typically done for you automatically by Grails, which manages your Hibernate session.

Hibernate caches database updates where possible, only actually pushing the changes when it knows that a flush is required, or when a flush is triggered programmatically. One common case where Hibernate will flush cached updates is when performing queries since the cached information might be included in the query results. But as long as you're doing non-conflicting saves, updates, and deletes, they'll be batched until the session is flushed. This can be a significant performance boost for applications that do a lot of database writes.

Note that flushing is not the same as committing a transaction. If your actions are performed in the context of a transaction, flushing will execute SQL updates but the database will save the changes in its transaction queue and only finalize the updates when the transaction commits.

5.3.1 Saving and Updating

This save will be not be pushed to the database immediately - it will be pushed when the next flush occurs. But there are occasions when you 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, deletes, etc. will be synchronized with the database. This also lets you catch any exceptions, which is typically useful in highly concurrent scenarios involving optimistic locking:

Another thing to bear in mind is that Grails validates a domain instance every time you save it. If that validation fails the domain instance will not be persisted to the database. By default, save() will simply return null in this case, but if you would prefer it to throw an exception you can use the failOnError argument:

You can even change the default behaviour with a setting in Config.groovy, as described in the section on configuration. Just remember that when you are saving domain instances that have been bound with data provided by the user, the likelihood of validation exceptions is quite high and you won't want those exceptions propagating to the end user.

You can find out more about the subtleties of saving data in this article - a must read!

5.3.2 Deleting Objects

As with saves, Hibernate will use transactional write-behind to perform the delete; to perform the delete in-place you can use the flush argument:

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

Using the flush argument lets you catch any errors that 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:

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, defining belongsTo will result in updates cascading from the owning class to its dependant (the other side of the relationship), and for many-/one-to-one and one-to-many relationships deletes will also cascade.

If you do not define belongsTo then no cascades will happen and you will have to manually save each object (except in the case of the one-to-many, in which case saves will cascade automatically if a new instance is in a hasMany collection).

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:

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. Also read part 2 of the GORM Gotchas series of articles to get a deeper understanding of relationships and cascading.

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:

GORM will execute a single SQL query to fetch the Airport instance, another to get its flights, and then 1 extra query for each iteration over the flights association to get the current flight's destination. In other words you get N+1 queries (if you exclude the original one to get the airport).

Configuring Eager Fetching

An alternative approach that avoids the N+1 queries is to use eager fetching, which can be specified as follows:

In this case the flights association will be loaded at the same time as its Airport instance, although a second query will be executed to fetch the collection. You can also use fetch: 'join' instead of lazy: false , in which case GORM will only execute a single query to get the airports and their flights. This works well for single-ended associations, but you need to be careful with one-to-manys. Queries will work as you'd expect right up to the moment you add a limit to the number of results you want. At that point, you will likely end up with fewer results than you were expecting. The reason for this is quite technical but ultimately the problem arises from GORM using a left outer join.

So, the recommendation is currently to use fetch: 'join' for single-ended associations and lazy: false for one-to-manys.

Be careful how and where you use eager loading because you could load your entire database into memory with too many eager associations. You can find more information on the mapping options in the section on 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. You can configure Hibernate to lazily fetch results in "batches". For example:

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
}
}

Check out part 3 of the GORM Gotchas series for more in-depth coverage of this tricky topic.

5.3.5 Pessimistic and Optimistic Locking

Optimistic Locking

By default GORM classes are configured for optimistic locking. Optimistic locking is a feature of Hibernate which involves storing a version value in a special version column in the database that is incremented after each update.

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. This will roll back the transaction if one is active.

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:

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.

The version will only be updated after flushing the session.

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 with the lock method:

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:

5.3.6 Modification Checking

Once you have loaded and possibly modified a persistent domain class instance, it isn't straightforward to retrieve the original values. If you try to reload the instance using get Hibernate will return the current modified instance from its Session cache. Reloading using another query would trigger a flush which could cause problems if your data isn't ready to be flushed yet. So GORM provides some methods to retrieve the original values that Hibernate caches when it loads the instance (which it uses for dirty checking).

isDirty

You can use the isDirty method to check if any field has been modified:

def airport = Airport.get(10)
assert !airport.isDirty()

airport.properties = params
if (airport.isDirty()) {
// do something based on changed state
}

isDirty() does not currently check collection associations, but it does check all other persistent properties and associations.

You can also check if individual fields have been modified:

def airport = Airport.get(10)
assert !airport.isDirty()

airport.properties = params
if (airport.isDirty('name')) {
// do something based on changed name
}

getDirtyPropertyNames

You can use the getDirtyPropertyNames method to retrieve the names of modified fields; this may be empty but will not be null:

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. Depending on the complexity of the query you have the following options in order of flexibility and power:

Dynamic Finders

Where Queries

Criteria Queries

Hibernate Query Language (HQL)

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

You can combine as many criteria as you like, but they must all be combined with And or all Or. If you need to combine And and Or or if the number of criteria creates a very long method name, just convert the query to a Criteria or HQL query.

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 and 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:

5.4.2 Where Queries

The where method, introduced in Grails 2.0, builds on the support for Detached Criteria by providing an enhanced, compile-time checked query DSL for common queries. The where method is more flexible than dynamic finders, less verbose than criteria and provides a powerful mechanism to compose queries.

Basic Querying

The where method accepts a closure that looks very similar to Groovy's regular collection methods. The closure should define the logical criteria in regular Groovy syntax, for example:

The returned object is a DetachedCriteria instance, which means it is not associated with any particular database connection or session. This means you can use the where method to define common queries at the class level:

Query execution is lazy and only happens upon usage of the DetachedCriteria instance. If you want to execute a where-style query immediately there are variations of the findAll and find methods to accomplish this:

Since the property subquery returns multiple results, the criterion used compares all results. For example the following query will find all people younger than people with the surname "Simpson":

Person.where {
age < property(age).of { lastName == "Simpson" }
}

Other Functions

There are several functions available to you within the context of a query. These are summarized in the table below:

Method

Description

second

The second of a date property

minute

The minute of a date property

hour

The hour of a date property

day

The day of the month of a date property

month

The month of a date property

year

The year of a date property

lower

Converts a string property to upper case

upper

Converts a string property to lower case

length

The length of a string property

trim

Trims a string property

Currently functions can only be applied to properties or associations of domain classes. You cannot, for example, use a function on a result of a subquery.

For example the following query can be used to find all pet's born in 2011:

def query = Pet.where {
year(birthDate) == 2011
}

You can also apply functions to associations:

def query = Person.where {
year(pets.birthDate) == 2009
}

Batch Updates and Deletes

Since each where method call returns a DetachedCriteria instance, you can use where queries to execute batch operations such as batch updates and deletes. For example, the following query will update all people with the surname "Simpson" to have the surname "Bloggs":

5.4.3 Criteria

Criteria is an advanced way to query that uses a Groovy builder to construct potentially complex queries. It is a much better approach than building up query strings using a StringBuffer.

Criteria can be used either with 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. For example:

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. Define a "projections" node within the criteria builder tree to use projections. There are equivalent methods within the projections node to the methods found in the Hibernate Projections class:

Using SQL Restrictions

Note that the parameter there is SQL. The first_name attribute referenced in the example refers to the persistence model, not the object model like in HQL queries. The Person property named firstName is mapped to the first_name column in the database and you must refer to that in the sqlRestriction string.

Also note that the SQL used here is not necessarily portable across databases.

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. This allows full access to all the properties in this class. This example calls setMaxResults and setFirstResult on the Criteria instance:

Notice the usage of the join method: it tells the criteria API to use a JOIN to fetch the named associations with the Task instances. It's probably best not to use this for one-to-many associations though, because you will most likely end up with duplicate results. Instead, use the 'select' fetch mode:

the flights collection would be loaded eagerly via a join even though the fetch mode has not been explicitly set.

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 { … }

Method

Description

list

This is the default method. It returns all matching rows.

get

Returns 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.

scroll

Returns a scrollable result set.

listDistinct

If 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.

count

Returns the number of matching rows.

5.4.4 Detached Criteria

Detached Criteria are criteria queries that are not associated with any given database session/connection. Supported since Grails 2.0, Detached Criteria queries have many uses including allowing you to create common reusable criteria queries, execute subqueries and execute batch updates/deletes.

Building Detached Criteria Queries

The primary point of entry for using the Detached Criteria is the grails.gorm.DetachedCriteria class which accepts a domain class as the only argument to its constructor:

import grails.gorm.*
…
def criteria = new DetachedCriteria(Person)

Once you have obtained a reference to a detached criteria instance you can execute where queries or criteria queries to build up the appropriate query. To build a normal criteria query you can use the build method:

Note that methods on the DetachedCriteria instance do not mutate the original object but instead return a new query. In other words, you have to use the return value of the build method to obtain the mutated criteria object:

Executing Detached Criteria Queries

Unlike regular criteria, Detached Criteria are lazy, in that no query is executed at the point of definition. Once a Detached Criteria query has been constructed then there are a number of useful query methods which are summarized in the table below:

Method

Description

list

List all matching entities

get

Return a single matching result

count

Count all matching records

exists

Return true if any matching records exist

deleteAll

Delete all matching records

updateAll(Map)

Update all matching records with the given properties

As an example the following code will list the first 4 matching records sorted by the firstName property:

Using Detached Criteria for Subqueries

Within the context of a regular criteria query you can use DetachedCriteria to execute subquery. For example if you want to find all people who are older than the average age the following query will accomplish that:

If the subquery class differs from the original criteria query then you will have to use the original syntax.

In the previous example the projection ensured that only a single result was returned (the average age). If your subquery returns multiple results then there are different criteria methods that need to be used to compare the result. For example to find all the people older than the ages 18 to 65 a gtAll query can be used:

The following table summarizes criteria methods for operating on subqueries that return multiple results:

Method

Description

gtAll

greater than all subquery results

geAll

greater than or equal to all subquery results

ltAll

less than all subquery results

leAll

less than or equal to all subquery results

eqAll

equal to all subquery results

neAll

not equal to all subquery results

Batch Operations with Detached Criteria

The DetachedCriteria class can be used to execute batch operations such as batch updates and deletes. For example, the following query will update all people with the surname "Simpson" to have the surname "Bloggs":

Notice the usage of withNewSession method above. Since events are triggered whilst Hibernate is flushing using persistence methods like save() and delete() won't result in objects being saved unless you run your operations with a new Session.

Fortunately the withNewSession method lets you share the same transactional JDBC connection even though you're using a different underlying Session.

The beforeValidate event

Fired before an object is validated.

class Person {
String name

static constraints = {
name size: 5..45
}

def beforeValidate() {
name = name?.trim()
}
}

The beforeValidate method is run before any validators are run.

Validation may run more often than you think. It is triggered by the validate() and save() methods as you'd expect, but it is also typically triggered just before the view is rendered as well. So when writing beforeValidate() implementations, make sure that they can handle being called multiple times with the same property values.

GORM supports an overloaded version of beforeValidate which accepts a List parameter which may include
the names of the properties which are about to be validated. This version of beforeValidate will be called
when the validate method has been invoked and passed a List of property names as an argument.

Note that when validate is triggered indirectly because of a call to the save method that
the validate method is being invoked with no arguments, not a List that includes all of
the property names.

Either or both versions of beforeValidate may be defined in a domain class. GORM will
prefer the List version if a List is passed to validate but will fall back on the
no-arg version if the List version does not exist. Likewise, GORM will prefer the
no-arg version if no arguments are passed to validate but will fall back on the
List version if the no-arg version does not exist. In that case, null is passed to beforeValidate.

The onLoad/beforeLoad event

Fired immediately before an object is loaded from the database:

class Person {
String name
Date dateCreated
Date lastUpdated

def onLoad() {
log.debug "Loading ${id}"
}
}

beforeLoad() is effectively a synonym for onLoad(), so only declare one or the other.

The afterLoad event

Fired immediately after an object is loaded from the database:

class Person {
String name
Date dateCreated
Date lastUpdated

def afterLoad() {
name = "I'm loaded"
}
}

Custom Event Listeners

As of Grails 2.0 there is a new API for plugins and applications to register and listen for persistence events. This API is not tied to Hibernate and also works for other persistence plugins such as the MongoDB plugin for GORM.

To use this API you need to subclass AbstractPersistenceEventListener (in package org.grails.datastore.mapping.engine.event ) and implement a single method called onPersistenceEvent. The simplest possible implementation can be seen below:

The AbstractPersistenceEvent class has many subclasses (PreInsertEvent, PostInsertEvent etc.) that provide further information specific to the event. A cancel() method is also provided on the event which allows you to veto an insert, update or delete operation.

Once you have created your event listener you need to register it with the ApplicationContext. This can be done in BootStrap.groovy:

Hibernate Events

It is generally encouraged to use the non-Hibernate specific API described above, but if you need access to more detailed Hibernate events then you can define custom Hibernate-specific event listeners.

You can also register event handler classes in an application's grails-app/conf/spring/resources.groovy or in the doWithSpring closure in a plugin descriptor by registering a Spring bean named hibernateEventListeners. This bean has one property, listenerMap which specifies the listeners to register for various Hibernate events.

The values of the Map are instances of classes that implement one or more Hibernate listener interfaces. You can use one class that implements all of the required interfaces, or one concrete class per interface, or any combination. The valid Map keys and corresponding interfaces are listed here:

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 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:

If you put nullable: false constraints on either dateCreated or lastUpdated, your domain instances will fail validation - probably not what you want. Leave constraints off these properties unless you have disabled automatic timestamping.

5.5.2 Custom ORM Mapping

Grails domain classes can be mapped onto many legacy schemas with an Object Relational Mapping DSL (domain specific language). The following sections takes you through what is possible with the ORM DSL.

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

You can also configure global mappings in Config.groovy (or an external config file) using this setting:

grails.gorm.default.mapping = {
version false
autoTimestamp false
}

It has the same syntax as the standard mapping block but it applies to all your domain classes! You can then override these defaults within the mapping block of a domain class.

5.5.2.1 Table and Column Names

Table names

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

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 to change the name you can do:

class Person {

String firstName

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

Here firstName is a dynamic method within the mapping Closure that has a single Map parameter. Since its name corresponds to a domain class persistent field, the parameter values (in this case just "column") are used to configure the mapping for that property.

Column type

GORM supports configuration of Hibernate types with the DSL using the type attribute. This includes specifing user types that implement the Hibernate org.hibernate.usertype.UserType interface, 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 default large-text type for the database you're using (for example TEXT or CLOB).

See the Hibernate documentation regarding Basic Types for further information.

Many-to-One/One-to-One Mappings

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

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 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 associations 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:

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. To change the column names you can specify a column within the mappings for each class.

Cache usages

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

read-only - If your application needs to read but never modify instances of a persistent class, a read-only cache may be used.

read-write - If the application needs to update data, a read-write cache might be appropriate.

nonstrict-read-write - If the application only occasionally needs to update data (ie. if it is very unlikely that two transactions would try to update the same item simultaneously) and strict transaction isolation is not required, a nonstrict-read-write cache might be appropriate.

transactional - The transactional cache strategy provides support for fully transactional cache providers such as JBoss TreeCache. Such a cache may only be used in a JTA environment and you must specify hibernate.transaction.manager_lookup_class in the grails-app/conf/DataSource.groovy file's hibernate config.

5.5.2.3 Inheritance Strategies

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

class Payment {
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:

Although you don't typically specify the id field (Grails adds it for you) you can still configure its mapping like the other properties. For example to customise the column for the id property you can do:

Domain classes mapped with composite primary keys must implement the Serializable interface and override the equals and hashCode methods, using the properties in the composite key for the calculations. The example above uses a HashCodeBuilder for convenience but it's fine to implement it yourself.

Another important consideration when using composite primary keys is associations. If for example you have a many-to-one association where the foreign keys are stored in the associated table then 2 columns will be present in the associated table.

For example consider the following domain class:

class Address {
Person person
}

In this case the address table will have an additional two columns called person_first_name and person_last_name. If you wish the change the mapping of these columns then you can do so using the following technique:

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 are used in which indexes:

Note that you cannot have any spaces in the value of the index attribute; in this example index:'Name_Idx, Address_Index' will cause an error.

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 that doesn't have version columns (or there's some other reason why you don't want/need this feature) you can disable this with the version method:

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 data (due to data overriding) unless you use pessimistic locking

Version columns types

By default Grails maps the version property as a Long that gets incremented by one each time an instance is updated. But Hibernate also supports using a Timestamp, for example:

import java.sql.Timestamp

class Person {

…
Timestamp version

static mapping = {
table 'people'
}
}

There's a slight risk that two updates occurring at nearly the same time on a fast server can end up with the same timestamp value but this risk is very low. One benefit of using a Timestamp instead of a Long is that you combine the optimistic locking and last-updated semantics into a single column.

5.5.2.8 Eager and Lazy Fetching

Lazy Collections

As discussed in the section on Eager and Lazy fetching, GORM collections are lazily loaded by default but you can change this behaviour with the ORM DSL. There are several options available to you, but the most common ones are:

lazy: false

fetch: 'join'

and they're used like this:

class Person {

String firstName
Pet pet

static hasMany = [addresses: Address]

static mapping = {
addresses lazy: false
pet fetch: 'join'
}
}

class Address {
String street
String postCode
}

class Pet {
String name
}

The first option, lazy: false , ensures that when a Person instance is loaded, its addresses collection is loaded at the same time with a second SELECT. The second option is basically the same, except the collection is loaded with a JOIN rather than another SELECT. Typically you want to reduce the number of queries, so fetch: 'join' is the more appropriate option. On the other hand, it could feasibly be the more expensive approach if your domain model and data result in more and larger results than would otherwise be necessary.

For more advanced users, the other settings available are:

batchSize: N

lazy: false, batchSize: N

where N is an integer. These let you fetch results in batches, with one query per batch. As a simple example, consider this mapping for Person:

class Person {

String firstName
Pet pet

static mapping = {
pet batchSize: 5
}
}

If a query returns multiple Person instances, then when we access the first pet property, Hibernate will fetch that Pet plus the four next ones. You can get the same behaviour with eager loading by combining batchSize with the lazy: false option. You can find out more about these options in the Hibernate user guide and this primer on fetching strategies. Note that ORM DSL does not currently support the "subselect" fetching strategy.

Lazy Single-Ended Associations

In GORM, one-to-one and many-to-one associations are by default lazy. Non-lazy single ended associations can be problematic when you load many entities because each non-lazy association will result in an extra SELECT statement. If the associated entities also have non-lazy associations, the number of queries grows significantly!

Use the same technique as for lazy collections to make a one-to-one or many-to-one association non-lazy/eager:

class Person {
String firstName
}

class Address {

String street
String postCode

static belongsTo = [person: Person]

static mapping = {
person lazy: false
}
}

Here we configure GORM to load the associated Person instance (through the person property) whenever an Address is loaded.

Lazy Single-Ended Associations and Proxies

Consider the previous example but with a lazily-loaded person association: Hibernate will set the person property to a proxy that is a subclass of Person. When you call any of the getters (except for the id property) or setters on that proxy, Hibernate will load the entity from the database.

Unfortunately this technique can produce surprising results. Consider the following example classes:

class Pet {
String name
}

class Dog extends Pet {
}

class Person {
String name
Pet pet
}

and assume that we have a single Person instance with a Dog as the pet. The following code will work as you would expect:

The second assertion fails, and to add to the confusion, this will work:

assert Pet.list()[0] instanceof Dog

What's going on here? It's down to a combination of how proxies work and the guarantees that the Hibernate session makes. When you load the Person instance, Hibernate creates a proxy for its pet relation and attaches it to the session. Once that happens, whenever you retrieve that Pet instance with a query, a get(), or the pet relation within the same session , Hibernate gives you the proxy.

Fortunately for us, GORM automatically unwraps the proxy when you use get() and findBy*(), or when you directly access the relation. That means you don't have to worry at all about proxies in the majority of cases. But GORM doesn't do that for objects returned with a query that returns a list, such as list() and findAllBy*(). However, if Hibernate hasn't attached the proxy to the session, those queries will return the real instances - hence why the last example works.

You can protect yourself to a degree from this problem by using the instanceOf method by GORM:

def person = Person.get(1)
assert Pet.list()[0].instanceOf(Dog)

However, it won't help here if casting is involved. For example, the following code will throw a ClassCastException because the first pet in the list is a proxy instance with a class that is neither Dog nor a sub-class of Dog:

def person = Person.get(1)
Dog pet = Pet.list()[0]

Of course, it's best not to use static types in this situation. If you use an untyped variable for the pet instead, you can access any Dog properties or methods on the instance without any problems.

These days it's rare that you will come across this issue, but it's best to be aware of it just in case. At least you will know why such an error occurs and be able to work around it.

5.5.2.9 Custom Cascade Behaviour

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

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

Valid settings for the cascade attribute include:

merge - merges the state of a detached association

save-update - cascades only saves and updates to an association

delete - cascades only deletes to an association

lock - useful if a pessimistic lock should be cascaded to its associations

refresh - cascades refreshes to an association

evict - cascades evictions (equivalent to discard() in GORM) to associations if set

all - cascade all operations to associations

all-delete-orphan - Applies only to one-to-many associations and indicates that when a child is removed from an association then it should be automatically deleted. Children are also deleted when the parent is.

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 recommendations for their usage

To specify the cascade attribute simply define one or more (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 (with the embedded property) to break a table into multiple objects. You can achieve a similar effect with Hibernate's custom user types. These are not domain classes themselves, but plain Java or Groovy classes. 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 explicitly define in the mapping what columns to use, since Hibernate can only use the property name for a single column. Fortunately, Grails lets you map multiple columns to a property using this syntax:

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, override the column's SQL type using the sqlType attribute:

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.2.11 Derived Properties

A derived property is one that takes its value from a SQL expression, often but not necessarily based on the value of one or more other persistent properties. Consider a Product class like this:

class Product {
Float price
Float taxRate
Float tax
}

If the tax property is derived based on the value of price and taxRate properties then is probably no need to persist the tax property. The SQL used to derive the value of a derived property may be expressed in the ORM DSL like this:

class Product {
Float price
Float taxRate
Float tax

static mapping = {
tax formula: 'PRICE * TAX_RATE'
}
}

Note that the formula expressed in the ORM DSL is SQL so references to other properties should relate to the persistence model not the object model, which is why the example refers to PRICE and TAX_RATE instead of price and taxRate.

With that in place, when a Product is retrieved with something like Product.get(42), the SQL that is generated to support that will look something like this:

select
product0_.id as id1_0_,
product0_.version as version1_0_,
product0_.price as price1_0_,
product0_.tax_rate as tax4_1_0_,
product0_.PRICE * product0_.TAX_RATE as formula1_0_
from
product product0_
where
product0_.id=?

Since the tax property is derived at runtime and not stored in the database it might seem that the same effect could be achieved by adding a method like getTax() to the Product class that simply returns the product of the taxRate and price properties. With an approach like that you would give up the ability query the database based on the value of the tax property. Using a derived property allows exactly that. To retrieve all Product objects that have a tax value greater than 21.12 you could execute a query like this:

Product.findAllByTaxGreaterThan(21.12)

Derived properties may be referenced in the Criteria API:

Product.withCriteria {
gt 'tax', 21.12f
}

The SQL that is generated to support either of those would look something like this:

Because the value of a derived property is generated in the database and depends on the execution of SQL code, derived properties may not have GORM constraints applied to them. If constraints are specified for a derived property, they will be ignored.

5.5.2.12 Custom Naming Strategy

By default Grails uses Hibernate's ImprovedNamingStrategy to convert domain class Class and field names to SQL table and column names by converting from camel-cased Strings to ones that use underscores as word separators. You can customize these on a per-instance basis in the mapping closure but if there's a consistent pattern you can specify a different NamingStrategy class to use.

Configure the class name to be used in grails-app/conf/DataSource.groovy in the hibernate section, e.g.

5.5.3 Default Sort Order

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

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

However, you can also declare the default sort order for a collection in the mapping:

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

The above means that all collections of Airport instances will by default be sorted by the airport name. If you also want to change the sort order , use this syntax:

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

Finally, you can configure sorting at the association level:

class Airport {
…
static hasMany = [flights: Flight]

static mapping = {
flights sort: 'number', order: 'desc'
}
}

In this case, the flights collection will always be sorted in descending order of flight number.

These mappings will not work for default unidirectional one-to-many or many-to-many relationships because they involve a join table. See this issue for more details. Consider using a SortedSet or queries with sort parameters to fetch the data you need.

5.6 Programmatic Transactions

Grails is built on Spring and uses Spring's Transaction abstraction for dealing with programmatic transactions. However, GORM classes have been enhanced to make this simpler with the withTransaction method. This method has a single parameter, a Closure, which has a single parameter which is a Spring TransactionStatus instance.

In this example we rollback the transaction if the destination account is not active. Also, if an unchecked Exception or Error (but not a checked Exception, even though Groovy doesn't require that you catch checked exceptions) is 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 properties:

String name
String description

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

Column

Data Type

name

varchar(255)

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 would likely define the column as follows if we were creating the table with an SQL script.

Column

Data Type

description

TEXT

Chances are we would 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 with constraints. We would 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, min, or 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 the specified constraint value requires more digits than default Hibernate column precision is (19 at the moment). For example:

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
Sponsored by SpringSource