When working with Grails domain models I often find myself wondering: How is this modeled in the database?

The combinations of hasMany, belongsTo, (and the occasional hasOne) lead to the one-to-many, many-to-many, many-to-one, and one-to-one associations. But how? What are these combinations? Well, feast your eyes on some Groovy and relational database porn.

One-to-many

In the first example, an Author has many Books, producing a one-to-many uni-directional relationship. Uni-directional meaning that an Author has a reference to its Books, however, a Book has no clue about its Author. The association is created with the hasMany static property in the Author domain class.

1
2
3
4
5
6
7
8
9
10
11
class Author {
    String name

    static hasMany = [books: Book]
}

class Book {
    String title
    int year
    String isbn
}

One-to-many

As shown in the database diagram, Grails creates a join table to represent the one-to-many association. The join table has two foreign key columns: the Author's ID, and the Book's ID.

It's worth nothing, since the Book does not have a reference to its Author, it's possible for multiple Authors to have the same Book. Notice how the author_book table makes this possible. To have Grails enforce that you want a Book to have a single Author, you'll need a bi-directional one-to-many association.

Bi-directional

With a bi-directional association, a Book is given a property which references its Author. This is done by adding a belongsTo static property to the Book class.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Author {
    String name

    static hasMany = [books: Book]
}

class Book {
    String title
    int year
    String isbn

    static belongsTo = [author: Author]
}

One-to-many bi-directional

Now, a foreign key is added to the Book containing the Author's ID. The join table is simply not used anymore. This implies that without an Author there can be no Book. Put differently, an Author owns its Books.

Many-to-many

A many-to-many association is created by using a hasMany static property in both domain classes. And, by using a belongsTo static property lacking a back-reference in the Book domain class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Author {
    String name

    static hasMany = [books: Book]
}

class Book {
    String title
    int year
    String isbn

    static hasMany = [authors: Author]
    static belongsTo = Author
}

Many-to-many

Like a uni-directional one-to-many, a many-to-many association uses a join table. In fact, at the database level it looks identical to a uni-directional one-to-many.

Many-to-one

Creating a uni-directional many-to-one association doesn't require hasMany or the like. It's just a matter of adding an instance property.

1
2
3
4
5
6
7
8
9
10
class Book {
    String title
    int year
    String isbn
    Publisher publisher
}

class Publisher {
    String name
}

Many-to-one

Bi-directional

A bi-directional many-to-one is created using the static belongsTo property. Surprisingly, this doesn't affect the database.

1
2
3
4
5
6
7
8
9
10
11
12
class Book {
    String title
    int year
    String isbn
    Publisher publisher
}

class Publisher {
    String name

    static belongsTo = [book: Book]
}

One-to-one

Finally, you get to see the static hasOne property in action!

1
2
3
4
5
6
7
8
9
10
class Author {
    String name

    static hasOne = [user: User]
}

class User {
    String username
    Author author
}

One-to-one

In the database, it looks just like a bi-directional one-to-many.

Enlightenment

As you've just read, it takes a precise combination of the hasMany, belongsTo and hasOne static properties, and sometimes an instance property, to assemble the various Grails domain class associations. Some are self-explanatory, others not so much. Either way, you may reference this guide when you need it.