Reputation: 1083
I'm trying to update a one to many association in Grails using the GORM events beforeInsert
and beforeUpdate
. Currently the beforeInsert
seems to be working, but beforeUpdate
always throws a TransientObjectException
on the hibernate flush.
The domains are mapped in the following way (an example, but hopefully enough to get the idea):
class Part {
String xml
static hasMany = [screws: Screws]
static mapping = {
screws cascade: "all-delete-orphan"
}
}
class Screw {
static belongsTo = Part
}
My update and insert essentially do the same thing and this method gets called from both beforeInsert
and beforeUpdate
(again a representative example):
private void augmentPartWithScrews() {
screws?.clear()
Set<Screw> parsedScrews = service.parseXmlAndReturnSetofScrews(xml)
parsedScrews.each {
addToScrews(it)
}
}
What I am seeing is that when I create a new Part it works, but when I update Part such that screws are deleted I get a TransientObjectException
in Hibernate's ForeignKeys
class. I did some debugging and found that when creating a new instance of Part
the objects come into the function getEntityIdentifierIfNotUnsaved
method as saved instances, but on update they come in as unsaved instances and thus the exception.
This is Grails 2.3.7 and Hibernate plugin 3.6.10.10
Upvotes: 0
Views: 654
Reputation: 546
We've found that trying to do inserts or deletes in the beforeInsert
or beforeUpdate
methods can be a real pain. The withNewSession
is almost always essential since you are effectively trying to modify the session while it's being flushed, causing untold confusion to Hibernate. However, when using withNewSession
, the screws
has already been loaded in a different session and will therefore be detached in this new session.
One think you might be able to do in this case is move the logic into a beforeValidate
method which is not tied into the session flushing behavior. There's a ticket open to add afterValidate
which is more along the lines of what you want (it's not there yet, though).
However, in this case, it might be best to just reverse the polarity and have a service update/save the new Parts and parse and add the screws instead of trying to put the logic into the domain object.
Upvotes: 1