|
I have a domain object that has a one-to-many relation to another object. Something like a Store hasMany Products and Product belongsTo Store.
In the controller, I have a method that removes a product from a Store, so i have something like this: Store store = Store.get(params.id) Product product = Product.get(params.productId) ... store.removeFromProducts(product) product.delete(flush:true) store.save(flush:true) Running the application, when I test this method, it works perfectly. However, when I try to test it in an integration test, I get the following error message: deleted object would be re-saved by cascade (remove deleted object from associations): [Product#100]; nested exception is org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade Debugging the code in the integration test, after calling removeFrom I see that the product is still in the list of products of the Store object. Debugging when running the application, after calling removeFrom I can see that the product was removed from list of products. Any ideas? Do you think this could be a bug? Thanks!
- Maricel
|
|
why are you flushing twice? And why can't you just say product.delete instead of loading the association parent from the db, shouldn't hibernate remove it from the collection automatically?
-----Original Message----- From: Maricel [mailto:[hidden email]] Sent: Monday, August 17, 2009 6:16 PM To: [hidden email] Subject: [grails-user] re[grails-user] moveFrom not working on integration test I have a domain object that has a one-to-many relation to another object. Something like a Store hasMany Products and Product belongsTo Store. In the controller, I have a method that removes a product from a Store, so i have something like this: Store store = Store.get(params.id) Product product = Product.get(params.productId) ... store.removeFromProducts(product) product.delete(flush:true) store.save(flush:true) Running the application, when I test this method, it works perfectly. However, when I try to test it in an integration test, I get the following error message: deleted object would be re-saved by cascade (remove deleted object from associations): [Product#100]; nested exception is org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade Debugging the code in the integration test, after calling removeFrom I see that the product is still in the list of products of the Store object. Debugging when running the application, after calling removeFrom I can see that the product was removed from list of products. Any ideas? Do you think this could be a bug? Thanks! -- View this message in context: http://www.nabble.com/removeFrom-not-working-on-integration-test-tp25016774p25016774.html Sent from the grails - user mailing list archive at Nabble.com. --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
I flush it twice as test to see if it works, but even though I just do:
product.delete store.save(flush:true) it doesn't work either. If I just do product.delete, that does not remove the association, neither if I just do store.removeFromProducts(product) without calling product.delete(). As far as I know, I need to remove the association first, using removeFrom and then delete the object. I read this in some forum (I cannot seem to find it right now), but anyway it works when running the application, it is in the integration test that it doesn't do anything, which is inconsistent.
- Maricel
|
|
I have a similar problem ... removeFrom works inside BootStrap.groovy but the exact code does not work in a controller. Have you worked out what the problem was?
|
|
It works fine in the controller when the application is running normally, but when testing the controller method that calls the removeFrom in an integration test, it doesn't work, not even with Grails 1.2
- Maricel
|
|
Have you found an answer to your question in the meantime?
I also experienced that an integration test obviously behaves differently than a controller even though the same methods are called... see http://n4.nabble.com/belongsTo-hasMany-addTo-removeTo-test-vs-production-td1744938.html#a1744938 for example where I didn't get any replies unfortunately. I suspect something in relation with GORM / Hibernate that behaves differently when called from a controller, e.g. in the chapter about GORM in the book "Grails 1.2" by Graeme Rocher and Jeff Brown it says that before executing a controller action, grails binds a new Hibernate session to the current thread and when it's ended and no exception was thrown the state of the session is synchronized with the DB. But actually I'm not sure why this should cause the stated different behaviours in integration tests. |
|
I am using Grails 1.3.1 and still have the same issue! No idea how to fix it or work around it!
- Maricel
|
|
In the meantime I've created an issue for what I think addresses that problem: https://cvs.codehaus.org/browse/GRAILS-6356
If you experience the same, just vote for it! :-] |
|
This fails in a controller too. addTo does three things - it initializes the collection if it's null, adds the instance to the collection, and sets the instance's back-reference to the owner. It's how you work with one-to-many and many-to-many relationships in Grails.
If you put the same code in a controller it also throws a NPE: def someAction = { def parent = new Parent(parentName:'parent').save(flush:true) def child = new Child(childName:'child', parent:parent).save(flush:true) // parent.addToChildren(child); // Without this line, Exception is thrown is assertion (children is null) println parent.children.size() render 'ok' } Burt > > In the meantime I've created an issue for what I think addresses that > problem: https://cvs.codehaus.org/browse/GRAILS-6356 > https://cvs.codehaus.org/browse/GRAILS-6356 > > If you experience the same, just vote for it! :-] > --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
Just re-opened the issue, because when using the scaffolded controller and saving a child with a parent, "println childInstance.parent.children.size();" returns 1 although no addTo is called anywhere:
def save = { def childInstance = new Child(params) if (childInstance.save(flush: true)) { flash.message = "${message(code: 'default.created.message', args: [message(code: 'child.label', default: 'Child'), childInstance.id])}" println childInstance.parent.children.size(); redirect(action: "show", id: childInstance.id) } else { render(view: "create", model: [childInstance: childInstance]) } } |
|
Again, you need to compare apples to apples. This equivalent integration test also passes:
class ParentChildTests extends GroovyTestCase { def sessionFactory void testParentChild() { def parent = new Parent(parentName:'parent').save(flush:true) sessionFactory.currentSession.clear() // simulate separate requests // fake out the form submission with proper values def params = [:] params."parent.id" = parent.id params.childName = 'child' def childInstance = new Child(params) childInstance.save(flush: true) assertEquals 1, childInstance.parent.children.size() } } It works because under the hood, the data binding (triggered by the Map constructor, new Child(params)) calls addTo. Burt > > Just re-opened the issue, because when using the scaffolded controller and > saving a child with a parent, "println > childInstance.parent.children.size();" returns 1 although no addTo is called > anywhere: > > def save = { > def childInstance = new Child(params) > if (childInstance.save(flush: true)) { > flash.message = "${message(code: 'default.created.message', > args: [message(code: 'child.label', default: 'Child'), childInstance.id])}" > println childInstance.parent.children.size(); > redirect(action: "show", id: childInstance.id) > } > else { > render(view: "create", model: [childInstance: childInstance]) > } > } > > --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
After some further testing, I saw that the following also works (not using a Map):
void testParentChild2() { def parent = new Parent(parentName:'parent').save(flush:true) sessionFactory.currentSession.clear() // simulate separate requests def childInstance = new Child(parent:parent, childName:'child').save(flush:true) assertEquals 1, childInstance.parent.children.size() } So the only thing that seems to make the difference here is clearing the session (if commented out, the test fails). How can that be explained in relation to GORM? |
| Powered by Nabble | Edit this page |
