| Acording to documentation default unsaved-value for Version is Undefined. "unsaved-value (optional - defaults to undefined): a version property value that indicates that an instance is newly instantiated (unsaved), distinguishing it from detached instances that were saved or loaded in a previous session. Undefined specifies that the identifier property value should be used." This means not null version is not enought to mark entity as not transient, in that case identifier unsaved-value is considered.
/**
* Assume the transient instance is newly instantiated if the version
* is null, otherwise defer to the identifier unsaved-value.
*/
public static final VersionValue UNDEFINED = new VersionValue() {
@Override
public final Boolean isUnsaved(Object version) {
LOG.trace( "Version unsaved-value strategy UNDEFINED" );
return version == null ? Boolean.TRUE : null;
}
But assume that identifier is assigned so it is not null during saveOrUpdate. In that case Hibernate hit database for entity with not null version to check if row coresponding to entity exsists. I have entity-A with collection of entity-B with cascade.all on it. Entity-B has embedded id, and all parts of that id are assigned dring buissness logic. Now, I'm doing saveOrUpdate for entity-A object. Collection of entity-B participates in saveOrUpdate because of cascade settings. For every object of entity-B ForeignKeys.isTransient() happening:
Boolean isUnsaved = session.getInterceptor().isTransient( entity );
if ( isUnsaved != null ) {
return isUnsaved;
}
I have detached object in collection so version is not null. Result of (in class VersionValue)
public final Boolean isUnsaved(Object version) {
LOG.trace( "Version unsaved-value strategy UNDEFINED" );
return version == null ? Boolean.TRUE : null;
}
is null. now checking by identifier strategy (in class ForeignKeys.isTransient()):
final EntityPersister persister = session.getEntityPersister( entityName, entity );
isUnsaved = persister.isTransient( entity, session );
if ( isUnsaved != null ) {
return isUnsaved;
}
and strategy for composite id returning allways null (in class IdentifierValue):
public static final IdentifierValue UNDEFINED = new IdentifierValue() {
@Override
public final Boolean isUnsaved(Object id) {
LOG.trace( "ID unsaved-value strategy UNDEFINED" );
return null;
}
So Hibernate hit the database for that object. Now, how I can fix this? Sure I can override isTransient in entity interceptor, but it affects all entities. I have to check object instance in this function and it afects performance. It would be better to change unsaved-value strategy for @Version only for those entities with embdeded keys or implement custom unsaved-value strategy for identifier. Both options are not possible with current Hibernate. Summary: @Version is not enought for entities with assigned identifiers. There is work around but with performance cost. Please fix it. |