I have a Note domain class, and when a new note is saved I need to create for it a NoteEvent, recording for posterity that the note has been created. Note has a collection of NoteEvents, and each NoteEvent keeps track of which Note it belongs to.

To handle the saving of new NoteEvents when a note was created, I was using afterInsert, because I’m saving note instances all over the place (it would be repetitive and time-consuming to have specific event-creating code after each saving of a new note), and beforeInsert obviously is not dealing with a persisted instance of Note yet — there will be nothing for the NoteEvent to have as its note.

But I also need to create a NoteEvent when one of these notes is updated, and this is where confusion and dismay and a significant lack of coffee come in. To attach a new “updated” NoteEvent to a note when it was updated, I brilliantly decided to use afterUpdate, again so as to avoid having the event creation code sprinkled all over the app whenever I needed to update a Note instance.

To add a new event to a note’s collection, I’m using the dynamic addTo() methods, which then require a save() of the instance. But in the case of an “after” event, this is a second call to save(). Thus when I first save a new instance and the afterInsert is called, the just-saved instance is immediately saved again, which causes the afterUpdate event to be fired, and now I have two note events: the “created” one from when I just saved the note, and an “updated” one from when the “created” one caused the note to be saved again.

It’s not clear to me how using “before” events instead could help in this situation. How else can I do this?

3 Answers
3

You can actually use beforeInsert and beforeUpdate methods. This is because the addTo* method does not require Note to be a persisted instance.

The NoteEvent will save when the Note saves because the NoteEvent is added before the Note is saved in the beforeUpdate method. Check out the addTo* docs for a longer explanation.

I was able to get both of the following Note classes to work how I believe you want them to. I did run into one issue where when updating Note two NoteEvent objects would be added. I was able to fix this by making sure that the update method of the controller was using noteInstance.save() instead of noteInstance.save(flush:true).

There's probably a way to do this, possible using beforeInsert and beforeUpdate since those wouldn't require saving the Note instance. The typical way to do secondary updates/inserts like this is to use withNewSession but in this case I'm not sure that it makes sense because that's more for creating an independent object, and you'd need to re-load the Note in the new session. Not that bad, but not performant.

One way to do this would be to remove the collection and save NoteEvent instances directly:

You lose cascading, so you'd want to delete a Note instance in a transactional service method so you can delete its associated NoteEvents. But that's really the solution to the whole problem. Just delete the afterInsert and afterUpdate callbacks and do all the work (creates, updates, and deletes) in transactional service methods. Whenever you do multiple database updates you should do them transactionally so they all succeed or all fail. This also meets your anti-clutter requirement since all of the work is encapsulated in the service.

Hmm… I agree that having centralized CRUD methods makes it easier to modify the behavior triggered by the various persistence events. But for my purposes (there’s a lot of existing code here that would be a ton of work to move around) using either before or after events on the domain class is preferable. The generated Grails controllers save the instances directly and I’m not in a position to change that now. BTW what I mean by “all over the place” is “in multiple controllers and potentially a service or two.” (This is indeed a bit of a warning sign, but this is in an established project…)
–
ebenezerJan 10 '13 at 15:40