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(); |