hibernate updating persistent records
We are using hibernate through the java based scripting language groovy.
We retrieve record, update record and save the record.
during update we clear the associations, and reload these before save.
We get an exception when Hibernate flushes the record after associations are deleted but before new ones are established, triggering a validation failure.
Ie we have a constraint on the associations:
class Entity {
...
static constraints = {
association1(minSize:1) //require association to have at least 1 record
}
}
What is the best approach to update a persistent record?
Some potential options:
==============================================
[1] create new record and copy over the properties:
def oldEntity = Entity.findByX(x)
if (oldEntity) {
oldEntity.properties = newEntity.properties
oldEntity.save(flush:true);|
}
else {
newEntity.save(flush:true);
}
The concern here is this feels hacky - creating a detatched entity and copying over the properties over a live one.
==============================================
[2] retrieve record, update, save, with flush disabled:
sessionFactory.currentSession.fl开发者_Python百科ushMode = org.hibernate.FlushMode.MANUAL
def existingEntity = Entity.findByX(x) existingEntity.association1.clear() existingEntity.association2.clear()
existingEntity.association1.add(new Association(...)) existingEntity.association2.add(new Association(...))
sessionFactory.currentSession.flushMode = org.hibernate.FlushMode.AUTO existingEntity.save(flush:true)
Not sure about this approach - don't like such interference with Hibernate's state management
==============================================
[3] Permanantly set flush mode to manual and use save() and save(flush:true) to persist records with cascade:"all-delete-orphan" to ensure associations are managed.
The question here is this is not the default - and relies on us to manage Hibernate's flushing.
==============================================
Summary:
All these approaches seem to smell - can anyone advise the least bad approach -or even best practice for this situation?
Thanks
alex
The solution we have gone with is to set the commit mode to "commit" which only refreshes with manual entity.save(flush:true) calls and at the end of the transaction if it doesn't rollback.
Config.groovy:
hibernate.flush.mode="commit"
We found as a quirk that setting this in DataSource.groovy didn't work although that's perhaps the more obvious place. Also new threads have required us to set it manually - the change was not automatically picked up.
EntityService.groovy:
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
def sessionFactory
... sessionFactory.currentSession.flushMode = org.hibernate.FlushMode.parse(CH.config.hibernate.flush.mode.toUpperCase())
This latter code only seems to be necessary in a threading case as new threads don't seem to be aware of this setting despite being otherwise context aware.
To me, if you really have to clear and recreate those association, the second approach is the one with less smell.
There's nothing wrong in setting flush mode to manual if you need to manipulate the model passing through invalid states.
精彩评论