Led & Sustained by

G2one Logo

Developed with

Intellij

Powered by

Spring

GORM - Defining relationships

&h1. Creating Relationships

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.

This documentation is for Grails 0.6 and later. For older versions see GORM - Defining Relationships (pre 0.6).

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. No other configuration is required, and changes to the referenced object will automatically be saved when the referencing object is saved.



A - Face.groovy
class Face {
    Nose nose
}






This sets up a relationship between a Face and a single Nose. If the Face is deleted, the Nose will not be deleted. This relationship is unidirectional currently, unless you add a reference in reverse from the Nose:

B - Nose.groovy
class Nose {
    Face face
}






In this scenario, deletion of either object will not result in cascaded deletion of the other object. If this were part of a 3D modelling system however noses might be part of a library of features, and as such deletion of the Nose may require all Faces using the Nose to be deleted. You just need to tell Grails that a Face "belongs" to a Nose instead. While the terminology in this example is slightly unusual it is easy to understand:

C - Face.groovy
class Face {
    static belongsTo = Nose

    Nose nose
}






This tells Grails that the Nose is the important piece here and that we are simply "using" it and do not own it.

Maintaining your references

Although we have created a two-way relationship here, setting:

myFace.nose = bigNose






...will not automatically do:

bigNose.face = myFace






You must implement this yourself, typically by implementing Face.setNose(Nose newNose) so that it assigns "this" to newNose.face.



One-to-many & Many-to-one

 Defining a one-to-many relationship is a simple matter of adding the mapping to the "hasMany" map. Defining a property of type Set is optional (before Grails 0.3 you needed to have "Set books" as well as the "hasMany ..."). If you want, you can define the property like this: "Set books = new HashSet()"

Author.groovy
class Author {
    static hasMany = [ books : Book ]

    String name
}






The ownership in a relationship is implied by a reference to (i.e. property of the type of) another domain class or by inclusion of the owned class in the hasMany map, detailed below.

One of the main features of Groovy is its support for static typing which means one-to-one and many-to-one relationships require no additions to the "relationships" map:

Book.groovy
class Book {
    Author author
    String title
}






For one-to-many's the owning side is assumed to be the "one" side of the relationship (in the above example this would be "Author.groovy").

Sometimes an owning class has more than one class in it's hasMany map:

Author.groovy
class Author {
    static hasMany = [books:Book, coBooks:Book]
    static mappedBy = [books:"mainAuthor", coBooks:"coAuthor"]

    String name
}


Book.groovy
class Book {
    static belongsTo = Author

    Author mainAuthor
    Author coAuthor
    String title
}






As you can see we have to use mappedBy for this case, to let the grails know how to map the fields since the hasMany map contains duplicate class.

A class can also belong to multiple related classes like this:

static belongsTo = [Author,Publisher]






In other words:

  • an owner can have belongings
  • belongings use the 'belongsTo' property to refer to their owner(s)
  • if an owner dies, all his belongings vanish, if the owner actually has direct references or an explicit hasMany relationship.

Many-to-many relationships (Since 0.4)

Many-to-many relationships can be defined by having a hasMany on each side of the relationship with at least one side having a belongsTo property:

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


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






If you do not specify a belongsTo for exactly one side of the relationship an error will be thrown.

The behaviour of a many-to-many relationship is that the "owning" side (in the above case Author) is the only side that can cascade updates. In other words doing the below will save both the Author and the Book:

new Author(..)
       .addBook(new Book(..))
       .save()

The add* methods are deprecated since Grails 0.5, use addTo* instead:

new Author(..)
       .addToBooks(new Book(..))
       .save()

 If you are using Grails 0.4.2 use add(to:'books', new Book(..)).

Since Author is the owner of this relationship this is possible, however you cannot add a new Author to a Book and save the Book expecting the update to cascade as only the owning side can cascade updates in this way.

Also, by default only saves and updates are cascaded from the owner and not deletes. The implication here is that you must explicitly delete a Book to remove it otherwise you will get orphaned instances.

See the Author/Book example and files on the Hibernate Integration page.

Composition (Since 0.5)

It is also possible to define components with GORM. In this case the association will not map to a separate table, but instead be in the same table as the owner of the composition. For example take the following classes:

class Person {
   String name
   Address homeAddress
   Address workAddress
   static embedded = ['homeAddress', 'workAddress']
}
class Address {
   String houseNumber
   String postCode
}






In this even though we have two classes the homeAddress and workAddress properties map to the person table in the following way:

Person Table

id name home_address_house_number

home_address_post_code

work_address_house_number

work_address_post_code
           

As you can see the Person class is composed to two Address classes at the domain model and database level.

</