Reputation: 757
If I use a GORM domain object in my Grails command object, the command object commits changes to the domain object automatically, even though I did not call the save() method.
I want to bind to GORM objects in the command object but without saving or committing changes to the database. If my controller or my service throw an exception, I want transaction rollback.
I can force the behavior I want with the following annotations, but that feels like I'm doing it the hard way.
Controller Class = @Transactional(readOnly = true)
Controller action method = @Transactional
Command Object Class = @Transactional(readOnly = true)
Service Class = @Transactional
Am I doing something wrong, are Grails domain objects supposed to get committed automatically by the command object unless I add all these annotations?
Upvotes: 0
Views: 980
Reputation: 75681
This isn't specific to command objects, it's a general feature of controller actions. By default the open-session-in-view pattern is active, where a Hibernate Session is created and bound to a thread-local before the action runs and it's flushed and closed after the action finishes. Any persistent instances retrieved from the database (either explicitly because of a query, or implicitly during data binding) will stay attached to the open session and are dirty-checked when the session flushes. Any modified instances will have their changes flushed along with other queued actions with or without a save()
call.
Making the entire method (or class) transactional and read-only is probably overkill. A more direct approach would be to either retrieve instances as read-only, e.g. using read()
instead of get()
, calling the readOnly
method when doing criteria queries, etc., or 'detaching' modified instances by calling the discard()
method on each. Another option is to clear the session at the end of the action so there's nothing to automatically flush, e.g.
AnyDomainClass.withSession { it.clear() }
Note that instances retrieved in 'read-only' mode can have their changes persisted, but Hibernate won't automatically do anything for those instances, it only happens when you explicitly call save()
.
Upvotes: 1