|
From: <hib...@li...> - 2006-07-21 16:53:05
|
Author: ste...@jb...
Date: 2006-07-21 12:52:30 -0400 (Fri, 21 Jul 2006)
New Revision: 10131
Modified:
trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java
trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
Log:
different approach to HHH-1927
Modified: trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java 2006-07-21 07:10:41 UTC (rev 10130)
+++ trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java 2006-07-21 16:52:30 UTC (rev 10131)
@@ -453,24 +453,6 @@
EntityEntry entry, //pass this as an argument only to avoid double looking
SessionImplementor source) {
- if ( entry == null && performDeepStateChecking() ) {
- // check to handle fringe case of merging the same "entity data" via
- // a transient instance within the same transaction it was saved; i.e.:
- // Session s = ...;
- // s.beginTransaction();
- // s.persist( new Entity( "someid" ) );
- // s.merge( new Entity( "someid" ) );
- // s.getTransaction().commit();
- EntityPersister persister = source.getEntityPersister( entityName, entity );
- Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
- if ( id != null ) {
- EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
- entry = source.getPersistenceContext().getEntry(
- source.getPersistenceContext().getEntity( key )
- );
- }
- }
-
if ( entry != null ) {
// the object is persistent as it has an entry associated with the
// session; so check its status
@@ -529,8 +511,4 @@
protected Boolean getAssumedUnsaved() {
return null;
}
-
- protected boolean performDeepStateChecking() {
- return false;
- }
}
Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java 2006-07-21 07:10:41 UTC (rev 10130)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java 2006-07-21 16:52:30 UTC (rev 10131)
@@ -17,6 +17,8 @@
import org.hibernate.event.MergeEvent;
import org.hibernate.event.MergeEventListener;
import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.EntityKey;
import org.hibernate.intercept.FieldInterceptionHelper;
import org.hibernate.intercept.FieldInterceptor;
import org.hibernate.persister.entity.EntityPersister;
@@ -85,15 +87,36 @@
event.setResult(entity);
}
else {
- event.setEntity(entity);
-
- int entityState = getEntityState(
- entity,
- event.getEntityName(),
- source.getPersistenceContext().getEntry(entity),
- source
- );
-
+
+ event.setEntity( entity );
+
+ int entityState = -1;
+
+ // Check the persistence context for an entry relating to this
+ // entity to be merged...
+ EntityEntry entry = source.getPersistenceContext().getEntry( entity );
+ if ( entry == null ) {
+ EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
+ Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
+ if ( id != null ) {
+ EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+ Object managedEntity = source.getPersistenceContext().getEntity( key );
+ entry = source.getPersistenceContext().getEntry( managedEntity );
+ if ( entry != null ) {
+ // we have specialized case of a detached entity from the
+ // perspective of the merge operation. Specifically, we
+ // have an incoming entity instance which has a corresponding
+ // entry in the current persistence context, but registered
+ // under a different entity instance
+ entityState = DETACHED;
+ }
+ }
+ }
+
+ if ( entityState == -1 ) {
+ entityState = getEntityState( entity, event.getEntityName(), entry, source );
+ }
+
switch (entityState) {
case DETACHED:
entityIsDetached(event, copyCache);
@@ -117,10 +140,6 @@
}
- protected boolean performDeepStateChecking() {
- return true;
- }
-
protected void entityIsPersistent(MergeEvent event, Map copyCache) {
log.trace("ignoring persistent instance");
@@ -151,7 +170,7 @@
final Serializable id = persister.hasIdentifierProperty() ?
persister.getIdentifier( entity, source.getEntityMode() ) :
null;
-
+
final Object copy = persister.instantiate( id, source.getEntityMode() ); //TODO: should this be Session.instantiate(Persister, ...)?
copyCache.put(entity, copy); //before cascade!
@@ -267,14 +286,51 @@
}
private boolean isVersionChanged(Object entity, EventSource source, EntityPersister persister, Object target) {
- return persister.isVersioned() &&
- !persister.getVersionType().isSame(
- persister.getVersion( target, source.getEntityMode() ),
- persister.getVersion( entity, source.getEntityMode() ),
- source.getEntityMode()
- );
+ if ( ! persister.isVersioned() ) {
+ return false;
+ }
+ // for merging of versioned entities, we consider the version having
+ // been changed only when:
+ // 1) the two version values are different;
+ // *AND*
+ // 2) The target actually represents database state!
+ //
+ // This second condition is a special case which allows
+ // an entity to be merged during the same transaction
+ // (though during a seperate operation) in which it was
+ // originally persisted/saved
+ boolean changed = persister.getVersionType().isSame(
+ persister.getVersion( target, source.getEntityMode() ),
+ persister.getVersion( entity, source.getEntityMode() ),
+ source.getEntityMode()
+ );
+
+ // TODO : perhaps we should additionally require that the incoming entity
+ // version be equivalent to the defined unsaved-value?
+ return changed && existsInDatabase( target, source, persister );
}
-
+
+ private boolean existsInDatabase(Object entity, EventSource source, EntityPersister persister) {
+ EntityEntry entry = source.getPersistenceContext().getEntry( entity );
+ if ( entry == null ) {
+ Serializable id = persister.getIdentifier( entity, source.getEntityMode() );
+ if ( id != null ) {
+ EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
+ Object managedEntity = source.getPersistenceContext().getEntity( key );
+ entry = source.getPersistenceContext().getEntry( managedEntity );
+ }
+ }
+
+ if ( entry == null ) {
+ // perhaps this should be an exception since it is only ever used
+ // in the above method?
+ return false;
+ }
+ else {
+ return entry.isExistsInDatabase();
+ }
+ }
+
protected void copyValues(
final EntityPersister persister,
final Object entity,
|