Sunday, July 20, 2008

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 it's not super obvious).

First Lesson: Don't set eager fetching globally
I by no means am a grails expert, but based on my experience don't 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 won't 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 it's 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 it's 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 isn't documented very well and it actually took me a little bit to figure out.

So lets say you have the following two domains

class Parent {
static hasMany = [kids: Kid]
String name
}

class Kid {
static belongsTo = [parent: Parent]
String name
}

And you save the following
new Parent(name: "James").addToKids(name: "Ayden").save()
Now Ayden turns 18 and going off to college and you need to remove him. You might think this would work:
Kid.findByName("Ayden").delete()
But it doesn't 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:
def kid = Kid.findByName("Ayden")
kid.parent.removeFromKids(kid)
kid.delete()

Why that isn't the default behavior in grails I don't know, but to prevent you from repeating code everywhere you can use Hibernate events. In the Kid Domain add the following beforeDelete property:
class Kid {
static belongsTo = [parent: Parent]
def beforeDelete = {
parent.removeFromKids(this)
}
String name
}

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.

9 comments:

Kamal Govindraj said...

On the eager fetching another thing to do would be to enable batch fetching or sub select fetching. Even if you forget to explicitly specify the fetch while querying hibernate will optimize the fetch (load associated objects / collections in batches rather one at a time), this would suffice for most cases.

Hibernate fetch strategy

For the parent child relationship it is probably better to modify the cascade attribute on the collection to all,orphan-delete. With this option you just need to remove the element from the parent collection and hibernate will delete the orphaned child object automatically.

Anonymous said...

I have a a one to many relationship where a parent has like thousands of kids, for which I have to do:

new Parent(name: "James").addToKids(name: "kid1").
.........
addTokids(name, "kid2000").save()

Is there a better way to do adding than this?. Any advices?

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Games, Entertaiment, Hobby, said...

Flyff private Flyff server top 100

Games, Entertaiment, Hobby, said...

Flyff private Flyff server top 100

said...

姫野愛MUTEKI吉野公佳鈴木早智子エロ動画YouTubeえろつべSEXエロ動画アダルトロリータMUTEKIおっぱいアダルトS1ニコニコ動画youtubeveohエロ動画ようつべエロ動画えろつべエロ動画SEXゆーちゅーぶ

東京ほっとアダルトH動画エロ動画JK・JCyoutubeエロ動画熟女ニコ動画S1エスワン無修正AV動画エロ動画ユーチューブYouTubeようつべAV無料パイパン近親相姦レイプ強姦中出し二宮沙樹パイズリ明日花キララ

said...

オーラルセックス手こきパイパンイラマチオパイズリパイズリみひろ蒼井そら穂花原紗央莉小澤マリア初音みのりRio(柚木ティナ)秋元美由北条麻妃妃乃ひかりかすみ果穂天海つばさ藤浦めぐAV女優アダルトエロ動画JKアダルトまんこ

人妻奥様熟女熟女アダルト エロ動画マダムパンチラアダルトフェラフェラパイズリ手こき手こき痴女熟女熟女熟女熟女美脚美尻巨乳熟女巨乳

Vinny said...

High grade assistance; I am going to undoubtedly come back to your website for extra know-how.
Memphis Locksmith