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 lazy. Non-lazy single ended associations 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 non-lazy using the same technique as for lazy collections:

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

Here we set the address property of the Person class will be eagerly fetched.

Lazy Single-Ended Associations and Proxies

In order to facilitate single-ended lazy associations Hibernate uses runtime generated proxies. The way this works is that Hibernate dynamically subclasses the proxied entity to create the proxy.

In the previous example Hibernate would create a subclass of Address and return that as a proxy to the real entity. When you call any of the getters or setters Hibernate will initialize the the entity from the database.

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

class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal {
	String name
}
class Owner {
	Animal pet
}

Given you have an Owner with a pet association that is a Dog consider the following code:

def owner = Owner.get(1)
def pet = Animal.get(owner.petId)
if(pet instanceof Dog) {
	// doesn't work!
}

Now you may think this code will work, but in fact it will not. The reason is Hibernate creates a dynamic proxy by subclassing Animal for the owner.pet association and caches it in the first level cache. So even if the actual proxied class is a Dog it won't be an instance of the Dog class due to the way proxies work.

The get around this problem GORM provides an instanceOf method that should always be used:

def owner = Owner.get(1)
def pet = Animal.get(owner.petId)
if(pet?.instanceof( Dog )) {
	// this works
}

However, there are cases where this particular Hibernate abstraction may still leak through. For example:

def owner = Owner.get(1)
Dog pet = Animal.get(owner.petId)

In this case you will get a ClassCastException because the proxied Animal is not a Dog even though the actual instance is a Dog.

Our best advice is to be aware of Hibernate proxies and how to deal with them when you do run into issues.