I think you meant by default eager
instead of lazy
in the first line of the question.
POINT TO REMEMBER
When associations are included in criteria query, they are by default eagerly fetched.
In your case you do not need the mapping books lazy:false
in Author
.
In terms of optimization I would vouch for the below approach:
class Author {
String name
static hasMany = [books: Book]
static mapping = {
//books lazy:false (DO NOT NEED)
}
}
class Book {
String bookName
//set belongsTo if you need bi-directional one-many
//books gets cascade deleted when author is deleted
//static belongsTo = [author: Author]
}
//Bootstrap
def author1 = new Author(name: "Dan Brown")
def book1 = new Book(bookName: "Da Vinci Code")
def book2 = new Book(bookName: "Angels And Demons")
def book3 = new Book(bookName: "Inferno")
[book1, book2, book3].each {author1.addToBooks(it)}
author1.save(flush: true, failOnError: true)
//Criteria
Author.createCriteria().list{
eq("name", "Dan Brown")
books{
//books are eagerly fetched by default using inner join. No need to specify FetchMode.
}
}
In terms of performance I would not go with the above approach if I have each Author who has wrote 20000 blogs(replace books with blogs). Eagerly fetching 20000 blogs for n
authors will be a performance hit. In this case I would go for lazy fetch (N + 1) route and try to filter out blogs as per my requirement. Something like below:
def author = Author.findByName("Dan Brown")
def books = author.books
//Assume you have a field publishedYear in Book
def booksReleasedIn2013 = author.books.findAll{it.publishedYear == 2013}
def booksReleasedBefore2013 = author.books.findAll{it.publishedYear < 2013}
assert "Inferno" in booksReleasedIn2013*.bookName
assert "Angels And Demons" in booksReleasedBefore2013*.bookName
If you do not have such(blogs case) case, then I would use the example cited above for both optimization and performance.