« Return to Thread: Domain object retains erroneous properties when in a Service

Re: Domain object retains erroneous properties when in a Service

by mykol :: Rate this Message:

Reply to Author | View in Thread

blogged about it too ;)

http://noisyheads.wordpress.com/2009/04/12/beware-controller-and-service-dirt-and-flush/

On Sun, Apr 12, 2009 at 12:49 AM, Burt Beckwith <burt@...> wrote:
I wrote this up in JIRA: http://jira.codehaus.org/browse/GRAILS-4426

Burt

> ah! so the setting of "properties" should happen inside the service, and not
> in the controller.
> *service:*
>
> def update(book, params)
> {
>   book.properties = params
>   ...
> }
>
> thanx for the tip! will give this a shot
>
> On Sun, Apr 12, 2009 at 12:03 AM, Burt Beckwith <burt@...>wrote:
>
> > I've found that you can load the domain instance in the controller (it
> > makes sense to do this there so you can more easily display an appropriate
> > message about missing id param, or existing param but instance not found,
> > etc.), but changes and the call to save() need to be done in the service.
> > The session is open the whole time due to the OpenSessionInView interceptor,
> > but the transaction is what's triggering an early flush.
> >
> > Burt
> >
> > > thanx burt. this is exactly what i did. i passed the whole map to the
> > > service instead, and removed all GORM prior to service execution. a bit
> > ugly
> > > though at the moment since i have to retrieve the Book instance, pass in
> > the
> > > properties, then invoke a validate() so that my gsp's render proper error
> > > messages everytime there's a failure. have to go this route since it's
> > all
> > > inside a "catch" (my services throw an exception to terminate the
> > > transaction)
> > >
> > > On Sat, Apr 11, 2009 at 11:24 PM, Burt Beckwith <burt@...
> > >wrote:
> > >
> > > > I've seen the same thing. I have a utility method in a service that
> > saves a
> > > > domain instance, and if it's not valid it logs the validation errors
> > and
> > > > calls discard(). The weird thing that I was seeing was that if there
> > was a
> > > > validation error for a database constraint (e.g. nullable or unique),
> > it
> > > > would save the instance and the constraint violation would throw an
> > > > exception. It never even hit my service method.
> > > >
> > > > I spent a lot of time in a debugger and haven't completely figured out
> > > > what's going on, but the call to getMetaClass() in the service ends the
> > > > transaction and triggers a flush. I'm not sure yet why that's
> > happening.
> > > >
> > > > All methods of a transactional service become transactional, even the
> > ones
> > > > added by Groovy, so a more fine-grained configuration like in
> > traditional
> > > > Spring using annotations, or even just discovering the "real" methods
> > and
> > > > making all of them transactional would avoid this.
> > > >
> > > > The core problem is that the instance was updated outside of the
> > service,
> > > > so dirty checking causes a flush. I reworked everything so I make all
> > > > changes in a service (the utility method is in the base class that all
> > > > services extend) and save the instance there. For a few parameters I
> > make an
> > > > explicit signature, e.g. "void updatePerson(person, username,
> > password)" and
> > > > extract the parameters in the controller, but if there are several I
> > punt
> > > > and pass in the whole params map, e.g. "void updatePerson(person,
> > params)".
> > > >
> > > > Burt
> > > >
> > > > > hi all,
> > > > > i've moved a lot of GORM calls to services instead of controllers.
> > this
> > > > is
> > > > > due to the fact i need transactions that spans more than one domain
> > > > class.
> > > > > unfortunately, when erroneous properties are set to the domain class,
> > > > they
> > > > > get retained or saved. to illustrate:
> > > > >
> > > > >
> > > > > *domain class:*
> > > > >
> > > > > class Book
> > > > > {
> > > > > String title
> > > > >  static constraints = {
> > > > > title(blank: false)
> > > > > }
> > > > > }
> > > > >
> > > > > service:
> > > > >
> > > > > *service method:*
> > > > >
> > > > > def update(book)
> > > > > {
> > > > > if(!book.hasErrors() || book.save())
> > > > > {
> > > > > //do something
> > > > > }
> > > > > else
> > > > > {
> > > > > throw new RuntimeException()
> > > > > }
> > > > >  ..
> > > > > ..
> > > > >
> > > > > }
> > > > >
> > > > > *controller method:*
> > > > >
> > > > > def update = {
> > > > > def book = Book.get(params['id'])
> > > > > book.properties = params
> > > > >  if(!book.hasErrors() && bookService.update(book)
> > > > >         {
> > > > >             ....
> > > > >         }
> > > > >         else
> > > > >
> > > > > ...
> > > > > }
> > > > >
> > > > >
> > > > >
> > > > > if the "title" i pass is blank, and invoke the update action, when i
> > go
> > > > to
> > > > > "show" or "browse" actions, i see that the book's title is now blank.
> > > > > although it did enter the "else" clause in the "update" action. but
> > > > somehow,
> > > > > the book retained the title property inserted to it.
> > > > >
> > > > >
> > > > > verified that without the service, and putting just
> > "if(!book.hasErrors()
> > > > ||
> > > > > book.save())" to the controller, this behavior is not seen.
> > > > >
> > > > > am i doing anything wrong?
> > > > >
> > > > > regards,
> > > > > mykol
> > > > >
> > > >
> > >
> >
>

 « Return to Thread: Domain object retains erroneous properties when in a Service