Jpa - Hibernate @Version incorrectly incremented
I'm using jpa with hibernate (3.2.7) as orm implementation. I have an entity being modified and then merged. I also have an @EntityListeners on this entity to ensure some attribute being valued.
If I change a value before merge, and then change back that value in @PreUpdate method inside Listener, setting the original value, my version on entity results incremented, but on database version has previous value. I think this is due to object didn't change, so on db it's not updated, but version on entity was alredy incremented without being restored after flush.
To explain better, i have this object:
@Entity
@EntityListeners({MyListener.class})
public class MyEntity {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String myValue;
@Version
private Long version ;
}
and this Listener:
public class MyListener {
@PreUpdate
public void preUpdate(MyEntity ua) {
ua.setMyValue("default");
}
}
Now suppose i have on db an object with these values: (id=1, myValue='defalut', version=1). I read this object, detach, pass it to client and get it back with myValue='new' and perform a merge operation (listener change myValue to 'default' and so object result unmodified to db), flush and exit from transaction (so is committed). After that i find version=2 on my object, but version=1 on db.
Is that an hibernate bug? Or a J开发者_如何学Pythonpa bug?
I would say this is an expected behavior. According to the Hibernate manual, @PreUpdate
is "Executed before the database UPDATE operation.". So, Hibernate has already figured out it has to do UPDATE by running the dirty check, and having it return true.
The dirty check can't happen AFTER @PreUpdate
, because Hibernate shouldn't call @PreUpdate
unless the dirty check is true. And if an update is going to be run, version should be incremented.
Have you thought about using a listener for @PrePersist
, instead of @PreUpdate
? I believe that's early enough in the process that it would be pre-dirty check, and thus have the behavior that you want.
For me it looks like specification violation. Or maybe that is too strong wording, better probably to say that such a corner case is not clearly enough specified. JPA 1.0 (Hibernate 3.2.7 being one of the implementations) specification spells quite clearly when version should be updated:
The version attribute is updated by the persistence provider runtime when the object is written to the database.
Also setting basic attribute in invoked entity is aloud (JPA 2.0):
A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
精彩评论