Showing posts with label learned. Show all posts
Showing posts with label learned. Show all posts
Sunday, January 29, 2017
Grails Lessons Learned
Grails Lessons Learned
Here are some lessons learned concerning lazy vs eager fetching and how to delete a child object in a One-to-many relationship (unfortunately its not super obvious).
First Lesson: Dont set eager fetching globally
I by no means am a grails expert, but based on my experience dont set the eager fetching in your Domain as the example shows (unless you have a very good reason and understand the consequences). Lazy vs Eager fetching is well described in the grails documentation, so I wont repeat it, but anyone using One-to-many relationships needs to know the differences.
The default behavior in grails is lazy fetching, which results in n+1 queries. In some cases this might be ideal, in others it may not. When its not you have a couple of choices. The example in the grails documentation sets a fetchMode property on the Domain. This sets it globally and every time the Domain is accessed, grails is going to load all its many relationships. The path I recommend is to specify the fetch mode when retrieving the data. For example, the list() method has a parameter called fetch and can be used like this: Book.list(fetch: [authors: "eager"]). This gives you the most flexibility by not specifying the fetch mode globally, but allowing you to fetch eagerly when necessary.
Second Lesson: Use Hibernate Events to help remove associations
Like myself, you might actually have a One-to-many relationship where you need to delete a child. Unfortunately this use case isnt documented very well and it actually took me a little bit to figure out.
So lets say you have the following two domains
And you save the followingclass Parent {
static hasMany = [kids: Kid]
String name
}
class Kid {
static belongsTo = [parent: Parent]
String name
}
Now Ayden turns 18 and going off to college and you need to remove him. You might think this would work:new Parent(name: "James").addToKids(name: "Ayden").save()
But it doesnt because the parent James still has a reference to the kid Ayden in the kids list (parent.kids). So you have to do the following:Kid.findByName("Ayden").delete()
Why that isnt the default behavior in grails I dont know, but to prevent you from repeating code everywhere you can use Hibernate events. In the Kid Domain add the following beforeDelete property:def kid = Kid.findByName("Ayden")
kid.parent.removeFromKids(kid)
kid.delete()
And now when you want to remove a Kid, all you need to do is call kid.delete(). The hibernate events are interesting. By default grails supports 4 events: beforeInsert, beforeUpdate, beforeDelete, onLoad. However, there is a recent plugin called Hibernate Events Plugin that adds 7 more events: beforeLoad, afterLoad, beforeSave, afterSave, afterInsert, afterUpdate, afterDelete.class Kid {
static belongsTo = [parent: Parent]
def beforeDelete = {
parent.removeFromKids(this)
}
String name
}
Available link for download
Subscribe to:
Posts (Atom)