|
View:
New views
11 Messages
—
Rating Filter:
Alert me
|
|
|
Domain object retains erroneous properties when in a Servicehi 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 |
|
|
Re: Domain object retains erroneous properties when in a ServiceI'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 > |
|
|
Re: Domain object retains erroneous properties when in a ServiceOn Sat, Apr 11, 2009 at 9:45 AM, Michael Mallete <mrmallete@...> wrote:
> } > service: > service method: > def update(book) > { > if(!book.hasErrors() || book.save()) > { > //do something > } > else > { > throw new RuntimeException() > } > .. > .. > } Do you want && in that condition, not || ? I assume that your intent is to throw the exception if save() fails. That is, in order to _not_ throw the exception the object needs to not have errors _and_ save needs to succeed. jb -- Jeff Brown SpringSource http://www.springsource.com/ Autism Strikes 1 in 166 Find The Cause ~ Find The Cure http://www.autismspeaks.org/ --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Domain object retains erroneous properties when in a Serviceoops sorry. yeah typo there, my actual codes uses &&
i was able to fix this somewhat. from how i understand, the hibernate session begins at the start of the initial GORM method call. from my code, i saw that i invoked a "get" from the controller to get the Book instance. this is then passed to the service, which in turn invokes it's own GORM methods (hasError and save). i really don't know if a session flush is invoked as soon as the controller invokes the service.
so what i did was to remove the "get" GORM method (and all GORM in the controller), and instead pass the params map to the service. any other ideas? On Sat, Apr 11, 2009 at 11:35 PM, Jeff Brown <jeff@...> wrote:
|
|
|
Re: Domain object retains erroneous properties when in a Servicethanx 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. |
|
|
Re: Domain object retains erroneous properties when in a ServiceI'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 > > > > > > |
|
|
Re: Domain object retains erroneous properties when in a Serviceah! 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. |
|
|
Re: Domain object retains erroneous properties when in a ServiceI 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 > > > > > > > > > > > > > > > |
|
|
Re: Domain object retains erroneous properties when in a Serviceblogged 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 |
|
|
Re: Domain object retains erroneous properties when in a ServiceHi,
That's exactly why I'm doing it withTransaction way - directly within a controller. I guess this is a serious bug because it makes services almost unusable for gorm stuff. I hope it is fixed as soon as possible. By the way as I can see, 1.1 is very buggy at the moment. I'm considering Grails for a one really huge web project (after I have successfully tried it for some small intranet applications) ... hope that all JIRA bugs are going to be fixed as soon as possible. Do you think it is production ready ? Cheers, Daniel On Sat, Apr 11, 2009 at 6:49 PM, Burt Beckwith <burt@...> wrote: I wrote this up in JIRA: http://jira.codehaus.org/browse/GRAILS-4426 |
|
|
Re: Domain object retains erroneous properties when in a ServiceHi everybody
I had the same problem. I solved it by first calling hasErrors() and validate() on the object, before delegating it to the update service. If the object hasErrors or does not validate I am calling discard() on it and rendering the object with it's errors in the view. This gets even more messy if you have nested objects - like a whole object tree - which you want to update: http://jira.codehaus.org/browse/GRAILS-4492 Eager fetching solves this problem, but my test sometimes fails and sometimes not... although the webtest never failed. I guess it's a integration test problem. Best Regards, Daniel
|
| Free embeddable forum powered by Nabble | Forum Help |