|
From: <hib...@li...> - 2006-03-22 14:58:14
|
Author: ste...@jb...
Date: 2006-03-22 09:57:59 -0500 (Wed, 22 Mar 2006)
New Revision: 9673
Added:
trunk/Hibernate3/src/org/hibernate/action/DelayedPostInsertIdentifier.java
trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/
trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java
trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyChild.java
trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.java
trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MySibling.java
Modified:
trunk/Hibernate3/src/org/hibernate/action/CollectionAction.java
trunk/Hibernate3/src/org/hibernate/action/EntityAction.java
trunk/Hibernate3/src/org/hibernate/action/EntityIdentityInsertAction.java
trunk/Hibernate3/src/org/hibernate/engine/PersistenceContext.java
trunk/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java
trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java
trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java
trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
trunk/Hibernate3/src/org/hibernate/event/def/DefaultPersistEventListener.java
trunk/Hibernate3/src/org/hibernate/event/def/DefaultReplicateEventListener.java
trunk/Hibernate3/src/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java
trunk/Hibernate3/test/org/hibernate/test/tm/CMTTest.java
Log:
HHH-1588 : delay post-insert-identifier-generator insertions on persist() outside of transaction
Modified: trunk/Hibernate3/src/org/hibernate/action/CollectionAction.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/action/CollectionAction.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/action/CollectionAction.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -22,6 +22,7 @@
private transient CollectionPersister persister;
private final Serializable key;
+ private Serializable finalKey;
private final SessionImplementor session;
private SoftLock lock;
private final String collectionRole;
@@ -75,7 +76,16 @@
}
protected final Serializable getKey() {
- return key;
+ finalKey = key;
+ if ( key instanceof DelayedPostInsertIdentifier ) {
+ // need to look it up from the persistence-context
+ finalKey = session.getPersistenceContext().getEntry( collection.getOwner() ).getId();
+ if ( finalKey == key ) {
+ // we may be screwed here since the collection action is about to execute
+ // and we do not know the final owner key value
+ }
+ }
+ return finalKey;
}
protected final SessionImplementor getSession() {
Added: trunk/Hibernate3/src/org/hibernate/action/DelayedPostInsertIdentifier.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/action/DelayedPostInsertIdentifier.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/action/DelayedPostInsertIdentifier.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -0,0 +1,49 @@
+package org.hibernate.action;
+
+import java.io.Serializable;
+
+/**
+ * Acts as a stand-in for an entity identifier which is supposed to be
+ * generated on insert (like an IDENTITY column) where the insert needed to
+ * be delayed because we were outside a transaction when the persist
+ * occurred (save currently still performs the insert).
+ * <p/>
+ * The stand-in is only used within the {@link org.hibernate.engine.PersistenceContext}
+ * in order to distinguish one instance from another; it is never injected into
+ * the entity instance or returned to the client...
+ *
+ * @author Steve Ebersole
+ */
+public class DelayedPostInsertIdentifier implements Serializable {
+ private static long SEQUENCE = 0;
+ private final long sequence;
+
+ public DelayedPostInsertIdentifier() {
+ synchronized( DelayedPostInsertIdentifier.class ) {
+ if ( SEQUENCE == Long.MAX_VALUE ) {
+ SEQUENCE = 0;
+ }
+ this.sequence = SEQUENCE++;
+ }
+ }
+
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+ final DelayedPostInsertIdentifier that = ( DelayedPostInsertIdentifier ) o;
+ return sequence == that.sequence;
+ }
+
+ public int hashCode() {
+ return ( int ) ( sequence ^ ( sequence >>> 32 ) );
+ }
+
+ public String toString() {
+ return "<delayed:" + sequence + ">";
+
+ }
+}
Modified: trunk/Hibernate3/src/org/hibernate/action/EntityAction.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/action/EntityAction.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/action/EntityAction.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -47,6 +47,9 @@
}
protected final Serializable getId() {
+ if ( id instanceof DelayedPostInsertIdentifier ) {
+ return session.getPersistenceContext().getEntry( instance ).getId();
+ }
return id;
}
Modified: trunk/Hibernate3/src/org/hibernate/action/EntityIdentityInsertAction.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/action/EntityIdentityInsertAction.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/action/EntityIdentityInsertAction.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -4,7 +4,9 @@
import java.io.Serializable;
import org.hibernate.HibernateException;
+import org.hibernate.AssertionFailure;
import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.EntityKey;
import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PreInsertEvent;
@@ -13,13 +15,21 @@
public final class EntityIdentityInsertAction extends EntityAction {
private final Object[] state;
+ private final boolean isDelayed;
+ private final EntityKey delayedEntityKey;
//private CacheEntry cacheEntry;
private Serializable generatedId;
- public EntityIdentityInsertAction(Object[] state, Object instance, EntityPersister persister, SessionImplementor session)
- throws HibernateException {
+ public EntityIdentityInsertAction(
+ Object[] state,
+ Object instance,
+ EntityPersister persister,
+ SessionImplementor session,
+ boolean isDelayed) throws HibernateException {
super( session, null, instance, persister );
this.state = state;
+ this.isDelayed = isDelayed;
+ delayedEntityKey = isDelayed ? generateDelayedEntityKey() : null;
}
public void execute() throws HibernateException {
@@ -62,6 +72,9 @@
}
private void postInsert() {
+ if ( isDelayed ) {
+ getSession().getPersistenceContext().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId );
+ }
PostInsertEventListener[] postListeners = getSession().getListeners()
.getPostInsertEventListeners();
if (postListeners.length>0) {
@@ -120,11 +133,14 @@
return generatedId;
}
+ public EntityKey getDelayedEntityKey() {
+ return delayedEntityKey;
+ }
+
+ private synchronized EntityKey generateDelayedEntityKey() {
+ if ( !isDelayed ) {
+ throw new AssertionFailure( "cannot request delayed entity-key for non-delayed post-insert-id generation" );
+ }
+ return new EntityKey( new DelayedPostInsertIdentifier(), getPersister(), getSession().getEntityMode() );
+ }
}
-
-
-
-
-
-
-
Modified: trunk/Hibernate3/src/org/hibernate/engine/PersistenceContext.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/engine/PersistenceContext.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/engine/PersistenceContext.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -431,4 +431,5 @@
*/
public void setReadOnly(Object entity, boolean readOnly);
+ void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId);
}
\ No newline at end of file
Modified: trunk/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -1098,6 +1098,27 @@
hasNonReadOnlyEntities = hasNonReadOnlyEntities || !readOnly;
}
+ public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
+ Object entity = entitiesByKey.remove( oldKey );
+ EntityEntry oldEntry = ( EntityEntry ) entityEntries.remove( entity );
+
+ EntityKey newKey = new EntityKey( generatedId, oldEntry.getPersister(), getSession().getEntityMode() );
+ addEntity( newKey, entity );
+ addEntry(
+ entity,
+ oldEntry.getStatus(),
+ oldEntry.getLoadedState(),
+ oldEntry.getRowId(),
+ generatedId,
+ oldEntry.getVersion(),
+ oldEntry.getLockMode(),
+ oldEntry.isExistsInDatabase(),
+ oldEntry.getPersister(),
+ oldEntry.isBeingReplicated(),
+ oldEntry.isLoadedWithLazyPropertiesUnfetched()
+ );
+ }
+
/**
* Used by the owning session to explicitly control serialization of the
* persistence context.
Modified: trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/event/def/AbstractSaveEventListener.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -67,22 +67,30 @@
source.getEntityPersister(entityName, entity),
false,
anything,
- source
+ source,
+ true
);
}
/**
* Prepares the save call using a newly generated id.
* @param entity The entity to be saved
+ * @param entityName The entity-name for the entity to be saved
* @param source The session which is the source of this save event.
- * @return The id used to save the entity
+ * @param requiresImmediateIdAccess does the event context require
+ * access to the identifier immediately after execution of this method (if
+ * not, post-insert style id generators may be postponed if we are outside
+ * a transaction).
+ * @return The id used to save the entity; may be null depending on the
+ * type of id generator used and the requiresImmediateIdAccess value
* @throws HibernateException
*/
protected Serializable saveWithGeneratedId(
Object entity,
String entityName,
Object anything,
- EventSource source)
+ EventSource source,
+ boolean requiresImmediateIdAccess)
throws HibernateException {
EntityPersister persister = source.getEntityPersister(entityName, entity);
@@ -97,7 +105,7 @@
return source.getIdentifier( entity );
}
else if ( generatedId == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) {
- return performSave(entity, null, persister, true, anything, source);
+ return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
}
else {
@@ -110,7 +118,7 @@
);
}
- return performSave(entity, generatedId, persister, false, anything, source);
+ return performSave( entity, generatedId, persister, false, anything, source, true );
}
}
@@ -122,7 +130,12 @@
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column in use?
* @param source The session from which the event originated.
- * @return The id used to save the entity.
+ * @param requiresImmediateIdAccess does the event context require
+ * access to the identifier immediately after execution of this method (if
+ * not, post-insert style id generators may be postponed if we are outside
+ * a transaction).
+ * @return The id used to save the entity; may be null depending on the
+ * type of id generator used and the requiresImmediateIdAccess value
* @throws HibernateException
*/
protected Serializable performSave(
@@ -131,7 +144,8 @@
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
- EventSource source)
+ EventSource source,
+ boolean requiresImmediateIdAccess)
throws HibernateException {
if ( log.isTraceEnabled() ) {
@@ -169,7 +183,8 @@
persister,
useIdentityColumn,
anything,
- source
+ source,
+ requiresImmediateIdAccess
);
}
@@ -200,7 +215,8 @@
* @param persister The entity's persister instance.
* @param useIdentityColumn Should an identity column be used for id generation?
* @param source The session which is the source of the current event.
- * @return The id used to save the entity.
+ * @return The id used to save the entity; may be null depending on the
+ * type of id generator used and the requiresImmediateIdAccess value
* @throws HibernateException
*/
protected Serializable performSaveOrReplicate(
@@ -209,14 +225,18 @@
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
- EventSource source)
+ EventSource source,
+ boolean requiresImmediateIdAccess)
throws HibernateException {
validate( entity, persister, source );
Serializable id = key==null ? null : key.getIdentifier();
- if (useIdentityColumn) {
+ boolean inTxn = source.getJDBCContext().isTransactionInProgress();
+ boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
+
+ if ( useIdentityColumn && !shouldDelayIdentityInserts ) {
log.trace("executing insertions");
source.getActionQueue().executeInserts();
}
@@ -263,15 +283,23 @@
.nullifyTransientReferences(values, types);
new Nullability(source).checkNullability( values, persister, false );
- if (useIdentityColumn) {
- EntityIdentityInsertAction insert = new EntityIdentityInsertAction(values, entity, persister, source);
- source.getActionQueue().execute(insert);
- id = insert.getGeneratedId();
- //now done in EntityIdentityInsertAction
- //persister.setIdentifier( entity, id, source.getEntityMode() );
- key = new EntityKey( id, persister, source.getEntityMode() );
- source.getPersistenceContext().checkUniqueness(key, entity);
- //source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
+ if ( useIdentityColumn ) {
+ EntityIdentityInsertAction insert = new EntityIdentityInsertAction( values, entity, persister, source, shouldDelayIdentityInserts );
+ if ( ! shouldDelayIdentityInserts ) {
+ log.debug( "executing identity-insert immediately" );
+ source.getActionQueue().execute(insert);
+ id = insert.getGeneratedId();
+ //now done in EntityIdentityInsertAction
+ //persister.setIdentifier( entity, id, source.getEntityMode() );
+ key = new EntityKey( id, persister, source.getEntityMode() );
+ source.getPersistenceContext().checkUniqueness(key, entity);
+ //source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
+ }
+ else {
+ log.debug( "delaying identity-insert due to no transaction in progress" );
+ source.getActionQueue().addAction( insert );
+ key = insert.getDelayedEntityKey();
+ }
}
Object version = Versioning.getVersion(values, persister);
Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultFlushEntityEventListener.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -10,6 +10,7 @@
import org.hibernate.HibernateException;
import org.hibernate.StaleObjectStateException;
import org.hibernate.action.EntityUpdateAction;
+import org.hibernate.action.DelayedPostInsertIdentifier;
import org.hibernate.classic.Validatable;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
@@ -41,6 +42,12 @@
public void checkId(Object object, EntityPersister persister, Serializable id, EntityMode entityMode)
throws HibernateException {
+ if ( id != null && id instanceof DelayedPostInsertIdentifier ) {
+ // this is a situation where the entity id is assigned by a post-insert generator
+ // and was saved outside the transaction forcing it to be delayed
+ return;
+ }
+
if ( persister.canExtractIdOutOfEntity() ) {
Serializable oid = persister.getIdentifier( object, entityMode );
Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultMergeEventListener.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -162,10 +162,10 @@
//graphs, since it helps ensure uniqueness
final Serializable requestedId = event.getRequestedId();
if (requestedId==null) {
- saveWithGeneratedId(copy, entityName, copyCache, source);
+ saveWithGeneratedId( copy, entityName, copyCache, source, false );
}
else {
- saveWithRequestedId(copy, requestedId, entityName, copyCache, source);
+ saveWithRequestedId( copy, requestedId, entityName, copyCache, source );
}
// cascade first, so that all unsaved objects get their
Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultPersistEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultPersistEventListener.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultPersistEventListener.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -128,7 +128,7 @@
final Object entity = source.getPersistenceContext().unproxy( event.getObject() );
if ( createCache.put(entity, entity)==null ) {
- saveWithGeneratedId( entity, event.getEntityName(), createCache, source );
+ saveWithGeneratedId( entity, event.getEntityName(), createCache, source, false );
}
}
Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultReplicateEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultReplicateEventListener.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultReplicateEventListener.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -120,7 +120,8 @@
persister,
regenerate,
replicationMode,
- source
+ source,
+ true
);
}
Modified: trunk/Hibernate3/src/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/src/org/hibernate/event/def/DefaultSaveOrUpdateEventListener.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -187,7 +187,8 @@
event.getEntity(),
event.getEntityName(),
null,
- event.getSession()
+ event.getSession(),
+ true
);
}
Added: trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/IdentityGeneratedKeysTest.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -0,0 +1,159 @@
+package org.hibernate.test.generatedkeys.identity;
+
+import org.hibernate.test.DatabaseSpecificTestCase;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * @author Steve Ebersole
+ */
+public class IdentityGeneratedKeysTest extends DatabaseSpecificTestCase {
+ public IdentityGeneratedKeysTest(String name) {
+ super( name );
+ }
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "generatedkeys/identity/MyEntity.hbm.xml" };
+ }
+
+ public boolean appliesTo(Dialect dialect) {
+ return dialect.supportsIdentityColumns();
+ }
+
+ public static Test suite() {
+ return new TestSuite( IdentityGeneratedKeysTest.class );
+ }
+
+ public void testIdentityColumnGeneratedIds() {
+ Session s = openSession();
+ s.beginTransaction();
+ MyEntity myEntity = new MyEntity( "test" );
+ Long id = ( Long ) s.save( myEntity );
+ assertNotNull( "identity column did not force immediate insert", id );
+ assertEquals( id, myEntity.getId() );
+ s.delete( myEntity );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testPersistOutsideTransaction() {
+ Session s = openSession();
+
+ // first test save() which should force an immediate insert...
+ MyEntity myEntity1 = new MyEntity( "test-save" );
+ Long id = ( Long ) s.save( myEntity1 );
+ assertNotNull( "identity column did not force immediate insert", id );
+ assertEquals( id, myEntity1.getId() );
+
+ // next test persist() which should cause a delayed insert...
+ long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+ MyEntity myEntity2 = new MyEntity( "test-persist");
+ s.persist( myEntity2 );
+ assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+ assertNull( myEntity2.getId() );
+
+ // an explicit flush should cause execution of the delayed insertion
+ s.flush();
+ assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 1, sfi().getStatistics().getEntityInsertCount() );
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ s.delete( myEntity1 );
+ s.delete( myEntity2 );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testPersistOutsideTransactionCascadedToNonInverseCollection() {
+ long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+ Session s = openSession();
+ MyEntity myEntity = new MyEntity( "test-persist");
+ myEntity.getNonInverseChildren().add( new MyChild( "test-child-persist-non-inverse" ) );
+ s.persist( myEntity );
+ assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+ assertNull( myEntity.getId() );
+ s.flush();
+ assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ s.createQuery( "delete MyChild" ).executeUpdate();
+ s.createQuery( "delete MyEntity" ).executeUpdate();
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testPersistOutsideTransactionCascadedToInverseCollection() {
+ long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+ Session s = openSession();
+ MyEntity myEntity2 = new MyEntity( "test-persist-2");
+ MyChild child = new MyChild( "test-child-persist-inverse" );
+ myEntity2.getInverseChildren().add( child );
+ child.setInverseParent( myEntity2 );
+ s.persist( myEntity2 );
+ assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+ assertNull( myEntity2.getId() );
+ s.flush();
+ assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ s.createQuery( "delete MyChild" ).executeUpdate();
+ s.createQuery( "delete MyEntity" ).executeUpdate();
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testPersistOutsideTransactionCascadedToManyToOne() {
+ long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+ Session s = openSession();
+ MyEntity myEntity = new MyEntity( "test-persist");
+ myEntity.setSibling( new MySibling( "test-persist-sibling-out" ) );
+ s.persist( myEntity );
+ assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+ assertNull( myEntity.getId() );
+ s.flush();
+ assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ s.createQuery( "delete MyEntity" ).executeUpdate();
+ s.createQuery( "delete MySibling" ).executeUpdate();
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testPersistOutsideTransactionCascadedFromManyToOne() {
+ long initialInsertCount = sfi().getStatistics().getEntityInsertCount();
+ Session s = openSession();
+ MyEntity myEntity2 = new MyEntity( "test-persist-2");
+ MySibling sibling = new MySibling( "test-persist-sibling-in" );
+ sibling.setEntity( myEntity2 );
+ s.persist( sibling );
+ assertEquals( "persist on identity column not delayed", initialInsertCount, sfi().getStatistics().getEntityInsertCount() );
+ assertNull( myEntity2.getId() );
+ s.flush();
+ assertEquals( "delayed persist insert not executed on flush", initialInsertCount + 2, sfi().getStatistics().getEntityInsertCount() );
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ s.createQuery( "delete MySibling" ).executeUpdate();
+ s.createQuery( "delete MyEntity" ).executeUpdate();
+ s.getTransaction().commit();
+ s.close();
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyChild.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyChild.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyChild.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -0,0 +1,41 @@
+package org.hibernate.test.generatedkeys.identity;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyChild {
+ private Long id;
+ private String name;
+ private MyEntity inverseParent;
+
+ public MyChild() {
+ }
+
+ public MyChild(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public MyEntity getInverseParent() {
+ return inverseParent;
+ }
+
+ public void setInverseParent(MyEntity inverseParent) {
+ this.inverseParent = inverseParent;
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.hbm.xml 2006-03-22 14:57:59 UTC (rev 9673)
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.generatedkeys.identity" default-access="field">
+
+ <class name="MyEntity" table="my_entity">
+ <id name="id">
+ <generator class="identity"/>
+ </id>
+ <property name="name"/>
+
+ <!-- used to test cascades "out" to a many-to-one association -->
+ <many-to-one name="sibling" class="MySibling" cascade="persist, merge"/>
+
+ <!-- used to test cascades "out" to non-inverse collections -->
+ <set name="nonInverseChildren" inverse="false" cascade="persist, merge">
+ <key column="non_inv_parent_id"/>
+ <one-to-many class="MyChild"/>
+ </set>
+
+ <!-- used to test cascades "out" to inverse collections -->
+ <set name="inverseChildren" inverse="true" cascade="persist, merge">
+ <key column="inv_parent_id"/>
+ <one-to-many class="MyChild"/>
+ </set>
+ </class>
+
+
+ <class name="MySibling" table="my_sibling">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name"/>
+ <many-to-one name="entity" class="MyEntity" cascade="persist, merge"/>
+ </class>
+
+
+ <class name="MyChild" table="my_child">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name"/>
+ <many-to-one name="inverseParent" column="inv_parent_id" class="MyEntity"/>
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MyEntity.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -0,0 +1,62 @@
+package org.hibernate.test.generatedkeys.identity;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyEntity {
+ private Long id;
+ private String name;
+ private MySibling sibling;
+ private Set nonInverseChildren = new HashSet();
+ private Set inverseChildren = new HashSet();
+
+ public MyEntity() {
+ }
+
+ public MyEntity(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public MySibling getSibling() {
+ return sibling;
+ }
+
+ public void setSibling(MySibling sibling) {
+ this.sibling = sibling;
+ }
+
+ public Set getNonInverseChildren() {
+ return nonInverseChildren;
+ }
+
+ public void setNonInverseChildren(Set nonInverseChildren) {
+ this.nonInverseChildren = nonInverseChildren;
+ }
+
+ public Set getInverseChildren() {
+ return inverseChildren;
+ }
+
+ public void setInverseChildren(Set inverseChildren) {
+ this.inverseChildren = inverseChildren;
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MySibling.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MySibling.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/test/org/hibernate/test/generatedkeys/identity/MySibling.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -0,0 +1,41 @@
+package org.hibernate.test.generatedkeys.identity;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MySibling {
+ private Long id;
+ private String name;
+ private MyEntity entity;
+
+ public MySibling() {
+ }
+
+ public MySibling(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public MyEntity getEntity() {
+ return entity;
+ }
+
+ public void setEntity(MyEntity entity) {
+ this.entity = entity;
+ }
+}
Modified: trunk/Hibernate3/test/org/hibernate/test/tm/CMTTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/tm/CMTTest.java 2006-03-22 13:11:03 UTC (rev 9672)
+++ trunk/Hibernate3/test/org/hibernate/test/tm/CMTTest.java 2006-03-22 14:57:59 UTC (rev 9673)
@@ -15,6 +15,7 @@
import org.hibernate.Session;
import org.hibernate.ScrollableResults;
import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.dialect.SybaseDialect;
import org.hibernate.transaction.CMTTransactionFactory;
import org.hibernate.util.SerializationHelper;
import org.hibernate.cfg.Configuration;
@@ -184,7 +185,10 @@
}
public void testConcurrentCachedDirtyQueries() throws Exception {
-
+ if ( reportSkip( "dead-lock bug", "concurrent queries", getDialect() instanceof SybaseDialect ) ) {
+ // sybase and sqlserver have serious locking issues here...
+ return;
+ }
DummyTransactionManager.INSTANCE.begin();
Session s = openSession();
Map foo = new HashMap();
|