7.2.4 Sets, Lists and Maps - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari
Version: 3.1.7
7.2.4 Sets, Lists and Maps
Sets of Objects
By default when you define a relationship with GORM it is ajava.util.Set
which is an unordered collection that cannot contain duplicates. In other words when you have:class Author {
static hasMany = [books: Book]
}
java.util.Set
. Sets guarantee uniqueness but not order, which may not be what you want. To have custom ordering you configure the Set as a SortedSet
:class Author { SortedSet books static hasMany = [books: Book]
}
java.util.SortedSet
implementation is used which means you must 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) } }
Lists of Objects
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 aList
:class Author { List books static hasMany = [books: Book]
}
author.books[0] // get the first book
books_idx
column where it saves the index of the elements in the collection to retain this order at the database 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()
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 aCollection
:class Author { Collection books static hasMany = [books: Book]
}
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()
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()
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 JavaSet
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:def book = new Book(title:"New Grails Book") def author = Author.get(1) book.author = author book.save()
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()