[hibernate-commits] Hibernate SVN: r17998 - in core/trunk/testsuite/src/test/java/org/hibernate/test: nonflushedchanges and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Nov 17 18:17:30 EST 2009


Author: gbadner
Date: 2009-11-17 18:17:25 -0500 (Tue, 17 Nov 2009)
New Revision: 17998

Added:
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/AbstractOperationTestCase.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Address.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competitor.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/CreateTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/DeleteTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employee.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/MergeTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/NumberedNode.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OneToOne.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OptLockEntity.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Person.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/PersonalDetails.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/SaveOrUpdateTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/TimestampedEntity.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/VersionedEntity.java
Log:
HHH-2762 : new unit tests for SessionImplementor.getNonFlushedChanges()/applyNonFlushedChanges() implementation

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/AbstractOperationTestCase.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/AbstractOperationTestCase.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/AbstractOperationTestCase.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,130 @@
+package org.hibernate.test.nonflushedchanges;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.NonFlushedChanges;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.StatefulPersistenceContext;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.test.tm.ConnectionProviderImpl;
+import org.hibernate.test.tm.TransactionManagerLookupImpl;
+import org.hibernate.transaction.CMTTransactionFactory;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public abstract class AbstractOperationTestCase extends FunctionalTestCase {
+	private Map oldToNewEntityRefs = new HashMap();
+
+	public AbstractOperationTestCase(String name) {
+		super( name );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.CONNECTION_PROVIDER, ConnectionProviderImpl.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, TransactionManagerLookupImpl.class.getName() );
+		cfg.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() );
+		cfg.setProperty( Environment.AUTO_CLOSE_SESSION, "true" );
+		cfg.setProperty( Environment.FLUSH_BEFORE_COMPLETION, "true" );
+		cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
+	}
+
+	public String[] getMappings() {
+		return new String[] {
+				"nonflushedchanges/Node.hbm.xml",
+				"nonflushedchanges/Employer.hbm.xml",
+				"nonflushedchanges/OptLockEntity.hbm.xml",
+				"nonflushedchanges/OneToOne.hbm.xml",
+				"nonflushedchanges/Competition.hbm.xml"
+		};
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	protected void clearCounts() {
+		getSessions().getStatistics().clear();
+	}
+
+	protected void assertInsertCount(int expected) {
+		int inserts = ( int ) getSessions().getStatistics().getEntityInsertCount();
+		assertEquals( "unexpected insert count", expected, inserts );
+	}
+
+	protected void assertUpdateCount(int expected) {
+		int updates = ( int ) getSessions().getStatistics().getEntityUpdateCount();
+		assertEquals( "unexpected update counts", expected, updates );
+	}
+
+	protected void assertDeleteCount(int expected) {
+		int deletes = ( int ) getSessions().getStatistics().getEntityDeleteCount();
+		assertEquals( "unexpected delete counts", expected, deletes );
+	}
+
+	protected void assertFetchCount(int count) {
+		int fetches = ( int ) getSessions().getStatistics().getEntityFetchCount();
+		assertEquals( count, fetches );
+	}
+
+	protected Session applyNonFlushedChangesToNewSessionCloseOldSession(Session oldSession) {
+		NonFlushedChanges nfc = ( ( SessionImplementor ) oldSession ).getNonFlushedChanges();
+		byte[] bytes = SerializationHelper.serialize( nfc );
+		NonFlushedChanges nfc2 = ( NonFlushedChanges ) SerializationHelper.deserialize( bytes );
+		Session newSession = openSession();
+		( ( SessionImplementor ) newSession ).applyNonFlushedChanges( nfc2 );
+		oldToNewEntityRefs.clear();
+		for ( Iterator it = ( ( SessionImplementor ) oldSession ).getPersistenceContext()
+				.getEntitiesByKey()
+				.entrySet()
+				.iterator(); it.hasNext(); ) {
+			Map.Entry entry = ( Map.Entry ) it.next();
+			EntityKey entityKey = ( EntityKey ) entry.getKey();
+			Object oldEntityRef = entry.getValue();
+			oldToNewEntityRefs.put(
+					oldEntityRef, ( ( SessionImplementor ) newSession ).getPersistenceContext().getEntity( entityKey )
+			);
+		}
+		for ( Iterator it = ( ( StatefulPersistenceContext ) ( ( SessionImplementor ) oldSession ).getPersistenceContext() )
+				.getProxiesByKey()
+				.entrySet()
+				.iterator(); it.hasNext(); ) {
+			Map.Entry entry = ( Map.Entry ) it.next();
+			EntityKey entityKey = ( EntityKey ) entry.getKey();
+			Object oldProxyRef = entry.getValue();
+			oldToNewEntityRefs.put(
+					oldProxyRef, ( ( SessionImplementor ) newSession ).getPersistenceContext().getProxy( entityKey )
+			);
+		}
+
+		oldSession.clear();
+		oldSession.close();
+		return newSession;
+	}
+
+	protected void applyNonFlushedChangesToClearedSession(Session s) {
+		NonFlushedChanges nfc = ( ( SessionImplementor ) s ).getNonFlushedChanges();
+		byte[] bytes = SerializationHelper.serialize( nfc );
+		NonFlushedChanges nfc2 = ( NonFlushedChanges ) SerializationHelper.deserialize( bytes );
+		s.clear();
+		( ( SessionImplementor ) s ).applyNonFlushedChanges( nfc2 );
+	}
+
+	protected Map getOldToNewEntityRefMap() {
+		return Collections.unmodifiableMap( oldToNewEntityRefs );
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Address.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Address.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Address.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,67 @@
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public class Address implements Serializable {
+	private Long id;
+	private String streetAddress;
+	private String city;
+	private String country;
+	private Person resident;
+
+	public Address() {
+	}
+
+	public Address(String streetAddress, String city, String country, Person resident) {
+		this.streetAddress = streetAddress;
+		this.city = city;
+		this.country = country;
+		this.resident = resident;
+		resident.setAddress( this );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getStreetAddress() {
+		return streetAddress;
+	}
+
+	public void setStreetAddress(String streetAddress) {
+		this.streetAddress = streetAddress;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getCountry() {
+		return country;
+	}
+
+	public void setCountry(String country) {
+		this.country = country;
+	}
+
+	public Person getResident() {
+		return resident;
+	}
+
+	public void setResident(Person resident) {
+		this.resident = resident;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.hbm.xml	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,31 @@
+<?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.nonflushedchanges">
+
+    <class name="Competition">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <list name="competitors" table="COMPET_ION_OR" cascade="persist,merge,delete">
+            <key column="TION_ID"/>
+            <list-index column="INDEX_COL"/>
+            <many-to-many class="Competitor" column="TOR_ID"/>
+        </list>
+    </class>
+
+    <class name="Competitor">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="name"/>
+    </class>
+
+</hibernate-mapping>
+

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competition.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,32 @@
+//$Id: $
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Emmanuel Bernard, Gail Badner (adapted this from "ops" tests version)
+ */
+public class Competition implements Serializable {
+	private Integer id;
+
+	private List competitors = new ArrayList();
+
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public List getCompetitors() {
+		return competitors;
+	}
+
+	public void setCompetitors(List competitors) {
+		this.competitors = competitors;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competitor.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competitor.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Competitor.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,36 @@
+//$Id: $
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+
+/**
+ * @author Emmanuel Bernard, Gail Badner (adapted this from "ops" tests version)
+ */
+public class Competitor implements Serializable {
+	public Integer id;
+	private String name;
+
+
+	public Competitor() {
+	}
+
+	public Competitor(String name) {
+		this.name = name;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/CreateTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/CreateTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/CreateTest.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,250 @@
+//$Id: CreateTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.nonflushedchanges;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.Session;
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+
+/**
+ * @author Gavin King, Gail Badner (adapted this from "ops" tests version)
+ */
+public class CreateTest extends AbstractOperationTestCase {
+
+	public CreateTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( CreateTest.class );
+	}
+
+	public void testNoUpdatesOnCreateVersionedWithCollection() throws Exception {
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		VersionedEntity root = new VersionedEntity( "root", "root" );
+		VersionedEntity child = new VersionedEntity( "c1", "child-1" );
+		root.getChildren().add( child );
+		child.setParent( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.save( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( VersionedEntity ) getOldToNewEntityRefMap().get( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( VersionedEntity ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+		assertDeleteCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( VersionedEntity ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertDeleteCount( 2 );
+	}
+
+	public void testCreateTree() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		root.addChild( child );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		System.out.println( "getting" );
+		root = ( Node ) s.get( Node.class, "root" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		Node child2 = new Node( "child2" );
+		root.addChild( child2 );
+		System.out.println( "committing" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+	}
+
+	public void testCreateTreeWithGeneratedId() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) s.get( NumberedNode.class, new Long( root.getId() ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		NumberedNode child2 = new NumberedNode( "child2" );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		root.addChild( child2 );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+	}
+
+	public void testCreateException() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node dupe = new Node( "dupe" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( dupe );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		dupe = ( Node ) getOldToNewEntityRefMap().get( dupe );
+		s.persist( dupe );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( dupe );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		try {
+			SimpleJtaTransactionManagerImpl.getInstance().commit();
+			assertFalse( true );
+		}
+		catch ( ConstraintViolationException cve ) {
+			//verify that an exception is thrown!
+		}
+		SimpleJtaTransactionManagerImpl.getInstance().rollback();
+
+		Node nondupe = new Node( "nondupe" );
+		nondupe.addChild( dupe );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( nondupe );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		try {
+			SimpleJtaTransactionManagerImpl.getInstance().commit();
+			assertFalse( true );
+		}
+		catch ( ConstraintViolationException cve ) {
+			//verify that an exception is thrown!
+		}
+		SimpleJtaTransactionManagerImpl.getInstance().rollback();
+	}
+
+	public void testCreateExceptionWithGeneratedId() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode dupe = new NumberedNode( "dupe" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( dupe );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		dupe = ( NumberedNode ) getOldToNewEntityRefMap().get( dupe );
+		s.persist( dupe );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		try {
+			s.persist( dupe );
+			assertFalse( true );
+		}
+		catch ( PersistentObjectException poe ) {
+			//verify that an exception is thrown!
+		}
+		SimpleJtaTransactionManagerImpl.getInstance().rollback();
+
+		NumberedNode nondupe = new NumberedNode( "nondupe" );
+		nondupe.addChild( dupe );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		try {
+			s.persist( nondupe );
+			assertFalse( true );
+		}
+		catch ( PersistentObjectException poe ) {
+			//verify that an exception is thrown!
+		}
+		SimpleJtaTransactionManagerImpl.getInstance().rollback();
+	}
+
+	public void testBasic() throws Exception {
+		Session s;
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		Employer er = new Employer();
+		Employee ee = new Employee();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.persist( ee );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		ee = ( Employee ) getOldToNewEntityRefMap().get( ee );
+		Collection erColl = new ArrayList();
+		Collection eeColl = new ArrayList();
+		erColl.add( ee );
+		eeColl.add( er );
+		er.setEmployees( erColl );
+		ee.setEmployers( eeColl );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		ee = ( Employee ) getOldToNewEntityRefMap().get( ee );
+		er = ( Employer ) ee.getEmployers().iterator().next();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		er = ( Employer ) s.load( Employer.class, er.getId() );
+		assertNotNull( er );
+		assertFalse( Hibernate.isInitialized( er ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		er = ( Employer ) getOldToNewEntityRefMap().get( er );
+		assertNotNull( er );
+		assertFalse( Hibernate.isInitialized( er ) );
+		assertNotNull( er.getEmployees() );
+		assertEquals( 1, er.getEmployees().size() );
+		Employee eeFromDb = ( Employee ) er.getEmployees().iterator().next();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		eeFromDb = ( Employee ) getOldToNewEntityRefMap().get( eeFromDb );
+		assertEquals( ee.getId(), eeFromDb.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+}
\ No newline at end of file

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/DeleteTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/DeleteTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/DeleteTest.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,94 @@
+package org.hibernate.test.nonflushedchanges;
+
+import junit.framework.Test;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public class DeleteTest extends AbstractOperationTestCase {
+	public DeleteTest(String name) {
+		super( name );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( DeleteTest.class );
+	}
+
+	public void testDeleteVersionedWithCollectionNoUpdate() throws Exception {
+		// test adapted from HHH-1564...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		VersionedEntity c = new VersionedEntity( "c1", "child-1" );
+		VersionedEntity p = new VersionedEntity( "root", "root" );
+		p.getChildren().add( c );
+		c.setParent( p );
+		s.save( p );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		VersionedEntity loadedParent = ( VersionedEntity ) s.get( VersionedEntity.class, "root" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		loadedParent = ( VersionedEntity ) getOldToNewEntityRefMap().get( loadedParent );
+		s.delete( loadedParent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 );
+		assertDeleteCount( 2 );
+	}
+
+	public void testNoUpdateOnDelete() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node node = new Node( "test" );
+		s.persist( node );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.delete( node );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+	}
+
+	public void testNoUpdateOnDeleteWithCollection() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node parent = new Node( "parent" );
+		Node child = new Node( "child" );
+		parent.getCascadingChildren().add( child );
+		s.persist( parent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		parent = ( Node ) s.get( Node.class, "parent" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		parent = ( Node ) getOldToNewEntityRefMap().get( parent );
+		s.delete( parent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+		assertDeleteCount( 2 );
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employee.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employee.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employee.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,35 @@
+//$Id: Employee.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+
+/**
+ * Employee in an Employer-Employee relationship
+ *
+ * @author Emmanuel Bernard, Gail Badner (adapted this from "ops" tests version)
+ */
+
+public class Employee implements Serializable {
+	private Integer id;
+	private Collection employers;
+
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer integer) {
+		id = integer;
+	}
+
+
+	public Collection getEmployers() {
+		return employers;
+	}
+
+	public void setEmployers(Collection employers) {
+		this.employers = employers;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.hbm.xml	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,39 @@
+<?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.nonflushedchanges">
+
+    <class name="Employer" polymorphism="explicit">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <version column="vers" name="vers"/>
+        <bag name="employees"
+             cascade="persist,merge"
+             table="EMPLOYER_EMPLOYEE">
+            <key column="EMPER_ID"/>
+            <many-to-many class="Employee" column="EMPEE_ID"/>
+        </bag>
+    </class>
+
+    <class name="Employee" polymorphism="explicit">
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <bag name="employers"
+             inverse="true"
+             cascade="persist,merge,save-update"
+             table="EMPLOYER_EMPLOYEE">
+            <key column="EMPEE_ID"/>
+            <many-to-many class="Employer" column="EMPER_ID"/>
+        </bag>
+    </class>
+
+</hibernate-mapping>
+

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Employer.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,44 @@
+//$Id: Employer.java 8670 2005-11-25 17:36:29Z epbernard $
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+
+/**
+ * Employer in a employer-Employee relationship
+ *
+ * @author Emmanuel Bernard, Gail Badner (adapted this from "ops" tests version)
+ */
+
+public class Employer implements Serializable {
+	private Integer id;
+	private Collection employees;
+	private Integer vers;
+
+	public Integer getVers() {
+		return vers;
+	}
+
+	public void setVers(Integer vers) {
+		this.vers = vers;
+	}
+
+
+	public Collection getEmployees() {
+		return employees;
+	}
+
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setEmployees(Collection set) {
+		employees = set;
+	}
+
+	public void setId(Integer integer) {
+		id = integer;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,126 @@
+//$Id: GetLoadTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.nonflushedchanges;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+
+
+/**
+ * @author Gavin King, Gail Badner (adapted this from "ops" tests version)
+ */
+public class GetLoadTest extends AbstractOperationTestCase {
+
+	public GetLoadTest(String str) {
+		super( str );
+	}
+
+	public void testGetLoad() throws Exception {
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Employer emp = new Employer();
+		s.persist( emp );
+		Node node = new Node( "foo" );
+		Node parent = new Node( "bar" );
+		parent.addChild( node );
+		s.persist( parent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		emp = ( Employer ) s.get( Employer.class, emp.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		emp = ( Employer ) getOldToNewEntityRefMap().get( emp );
+		assertTrue( Hibernate.isInitialized( emp ) );
+		assertFalse( Hibernate.isInitialized( emp.getEmployees() ) );
+		node = ( Node ) s.get( Node.class, node.getName() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		node = ( Node ) getOldToNewEntityRefMap().get( node );
+		emp = ( Employer ) getOldToNewEntityRefMap().get( emp );
+		assertTrue( Hibernate.isInitialized( node ) );
+		assertFalse( Hibernate.isInitialized( node.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( node.getParent() ) );
+		assertNull( s.get( Node.class, "xyz" ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		emp = ( Employer ) s.load( Employer.class, emp.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		emp = ( Employer ) getOldToNewEntityRefMap().get( emp );
+		emp.getId();
+		assertFalse( Hibernate.isInitialized( emp ) );
+		node = ( Node ) s.load( Node.class, node.getName() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		node = ( Node ) getOldToNewEntityRefMap().get( node );
+		assertEquals( node.getName(), "foo" );
+		assertFalse( Hibernate.isInitialized( node ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		emp = ( Employer ) s.get( "org.hibernate.test.nonflushedchanges.Employer", emp.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		emp = ( Employer ) getOldToNewEntityRefMap().get( emp );
+		assertTrue( Hibernate.isInitialized( emp ) );
+		node = ( Node ) s.get( "org.hibernate.test.nonflushedchanges.Node", node.getName() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		node = ( Node ) getOldToNewEntityRefMap().get( node );
+		assertTrue( Hibernate.isInitialized( node ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		emp = ( Employer ) s.load( "org.hibernate.test.nonflushedchanges.Employer", emp.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		emp = ( Employer ) getOldToNewEntityRefMap().get( emp );
+		emp.getId();
+		assertFalse( Hibernate.isInitialized( emp ) );
+		node = ( Node ) s.load( "org.hibernate.test.nonflushedchanges.Node", node.getName() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		emp = ( Employer ) getOldToNewEntityRefMap().get( emp );
+		node = ( Node ) getOldToNewEntityRefMap().get( node );
+		assertEquals( node.getName(), "foo" );
+		assertFalse( Hibernate.isInitialized( node ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertFetchCount( 0 );
+	}
+
+	public void testGetAfterDelete() throws Exception {
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Employer emp = new Employer();
+		s.persist( emp );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( emp );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		emp = ( Employer ) s.get( Employee.class, emp.getId() );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertNull( "get did not return null after delete", emp );
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( GetLoadTest.class );
+	}
+}
+


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/GetLoadTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/MergeTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/MergeTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/MergeTest.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,844 @@
+//$Id: MergeTest.java 11037 2007-01-09 16:04:16Z steve.ebersole at jboss.com $
+package org.hibernate.test.nonflushedchanges;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.Session;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.criterion.Projections;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+
+/**
+ * @author Gavin King, Gail Badner (adapted this from "ops" tests version)
+ */
+public class MergeTest extends AbstractOperationTestCase {
+
+	public MergeTest(String str) {
+		super( str );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( MergeTest.class );
+	}
+
+	public void testMergeStaleVersionFails() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		VersionedEntity entity = new VersionedEntity( "entity", "entity" );
+		s.persist( entity );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		// make the detached 'entity' reference stale...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		VersionedEntity entity2 = ( VersionedEntity ) s.get( VersionedEntity.class, entity.getId() );
+		entity2.setName( "entity-name" );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		// now try to reattch it
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		try {
+			s.merge( entity );
+			s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+			entity = ( VersionedEntity ) getOldToNewEntityRefMap().get( entity );
+			SimpleJtaTransactionManagerImpl.getInstance().commit();
+			fail( "was expecting staleness error" );
+		}
+		catch ( StaleObjectStateException expected ) {
+			// expected outcome...
+		}
+		finally {
+			SimpleJtaTransactionManagerImpl.getInstance().rollback();
+		}
+	}
+
+	public void testMergeBidiPrimayKeyOneToOne() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Person p = new Person( "steve" );
+		new PersonalDetails( "I have big feet", p );
+		s.persist( p );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		p.getDetails().setSomePersonalDetail( p.getDetails().getSomePersonalDetail() + " and big hands too" );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		p = ( Person ) s.merge( p );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		p = ( Person ) getOldToNewEntityRefMap().get( p );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 1 );
+		assertDeleteCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( p );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testMergeBidiForeignKeyOneToOne() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Person p = new Person( "steve" );
+		Address a = new Address( "123 Main", "Austin", "US", p );
+		s.persist( a );
+		s.persist( p );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		p.getAddress().setStreetAddress( "321 Main" );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		p = ( Person ) s.merge( p );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 ); // no cascade
+		assertDeleteCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( a );
+		s.delete( p );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testNoExtraUpdatesOnMerge() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node node = new Node( "test" );
+		s.persist( node );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		// node is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		node = ( Node ) s.merge( node );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		node.setDescription( "new description" );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		node = ( Node ) s.merge( node );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+		assertUpdateCount( 1 );
+		assertInsertCount( 0 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+	}
+
+	public void testNoExtraUpdatesOnMergeWithCollection() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node parent = new Node( "parent" );
+		Node child = new Node( "child" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		s.persist( parent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		// parent is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		parent = ( Node ) s.merge( parent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		( ( Node ) parent.getChildren().iterator().next() ).setDescription( "child's new description" );
+		parent.addChild( new Node( "second child" ) );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		parent = ( Node ) s.merge( parent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+		assertUpdateCount( 1 );
+		assertInsertCount( 1 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+	}
+
+	public void testNoExtraUpdatesOnMergeVersioned() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		VersionedEntity entity = new VersionedEntity( "entity", "entity" );
+		s.persist( entity );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		// entity is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		VersionedEntity mergedEntity = ( VersionedEntity ) s.merge( entity );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		mergedEntity = ( VersionedEntity ) getOldToNewEntityRefMap().get( mergedEntity );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+		assertEquals( "unexpected version increment", entity.getVersion(), mergedEntity.getVersion() );
+
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		entity.setName( "new name" );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		entity = ( VersionedEntity ) s.merge( entity );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+		assertUpdateCount( 1 );
+		assertInsertCount( 0 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+	}
+
+	public void testNoExtraUpdatesOnMergeVersionedWithCollection() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		VersionedEntity parent = new VersionedEntity( "parent", "parent" );
+		VersionedEntity child = new VersionedEntity( "child", "child" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		s.persist( parent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		// parent is now detached, but we have made no changes.  so attempt to merge it
+		// into this new session; this should cause no updates...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		VersionedEntity mergedParent = ( VersionedEntity ) s.merge( parent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		mergedParent = ( VersionedEntity ) getOldToNewEntityRefMap().get( mergedParent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+		assertEquals( "unexpected parent version increment", parent.getVersion(), mergedParent.getVersion() );
+		VersionedEntity mergedChild = ( VersionedEntity ) mergedParent.getChildren().iterator().next();
+		assertEquals( "unexpected child version increment", child.getVersion(), mergedChild.getVersion() );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node while it is detached and
+		// make sure we get an update as a result...
+		mergedParent.setName( "new name" );
+		mergedParent.getChildren().add( new VersionedEntity( "child2", "new child" ) );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		parent = ( VersionedEntity ) s.merge( mergedParent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		parent = ( VersionedEntity ) getOldToNewEntityRefMap().get( parent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+		assertUpdateCount( 1 );
+		assertInsertCount( 1 );
+		///////////////////////////////////////////////////////////////////////
+
+		cleanup();
+	}
+
+	public void testNoExtraUpdatesOnPersistentMergeVersionedWithCollection() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		VersionedEntity parent = new VersionedEntity( "parent", "parent" );
+		VersionedEntity child = new VersionedEntity( "child", "child" );
+		parent.getChildren().add( child );
+		child.setParent( parent );
+		s.persist( parent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		// parent is now detached, but we have made no changes. so attempt to merge it
+		// into this new session; this should cause no updates...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		// load parent so that merge will follow entityIsPersistent path
+		VersionedEntity persistentParent = ( VersionedEntity ) s.get( VersionedEntity.class, parent.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		persistentParent = ( VersionedEntity ) getOldToNewEntityRefMap().get( persistentParent );
+		// load children
+		VersionedEntity persistentChild = ( VersionedEntity ) persistentParent.getChildren().iterator().next();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		persistentParent = ( VersionedEntity ) getOldToNewEntityRefMap().get( persistentParent );
+		VersionedEntity mergedParent = ( VersionedEntity ) s.merge( persistentParent ); // <-- This merge leads to failure
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		mergedParent = ( VersionedEntity ) getOldToNewEntityRefMap().get( mergedParent );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertUpdateCount( 0 );
+		assertInsertCount( 0 );
+		assertEquals( "unexpected parent version increment", parent.getVersion(), mergedParent.getVersion() );
+		VersionedEntity mergedChild = ( VersionedEntity ) mergedParent.getChildren().iterator().next();
+		assertEquals( "unexpected child version increment", child.getVersion(), mergedChild.getVersion() );
+
+		///////////////////////////////////////////////////////////////////////
+		// as a control measure, now update the node once it is loaded and
+		// make sure we get an update as a result...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		persistentParent = ( VersionedEntity ) s.get( VersionedEntity.class, parent.getId() );
+		persistentParent.setName( "new name" );
+		persistentParent.getChildren().add( new VersionedEntity( "child2", "new child" ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		persistentParent = ( VersionedEntity ) getOldToNewEntityRefMap().get( persistentParent );
+		persistentParent = ( VersionedEntity ) s.merge( persistentParent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+		assertUpdateCount( 1 );
+		assertInsertCount( 1 );
+		///////////////////////////////////////////////////////////////////////
+
+		// cleanup();
+	}
+
+	public void testPersistThenMergeInSameTxnWithVersion() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		VersionedEntity entity = new VersionedEntity( "test", "test" );
+		s.persist( entity );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.merge( new VersionedEntity( "test", "test-2" ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+
+		try {
+			// control operation...
+			s.saveOrUpdate( new VersionedEntity( "test", "test-3" ) );
+			fail( "saveOrUpdate() should fail here" );
+		}
+		catch ( NonUniqueObjectException expected ) {
+			// expected behavior
+		}
+
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testPersistThenMergeInSameTxnWithTimestamp() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		TimestampedEntity entity = new TimestampedEntity( "test", "test" );
+		s.persist( entity );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.merge( new TimestampedEntity( "test", "test-2" ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+
+		try {
+			// control operation...
+			s.saveOrUpdate( new TimestampedEntity( "test", "test-3" ) );
+			fail( "saveOrUpdate() should fail here" );
+		}
+		catch ( NonUniqueObjectException expected ) {
+			// expected behavior
+		}
+
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testMergeDeepTree() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		Node grandchild = new Node( "grandchild" );
+		root.addChild( child );
+		child.addChild( grandchild );
+		s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		grandchild.setDescription( "the grand child" );
+		Node grandchild2 = new Node( "grandchild2" );
+		child.addChild( grandchild2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 1 );
+		clearCounts();
+
+		Node child2 = new Node( "child2" );
+		Node grandchild3 = new Node( "grandchild3" );
+		child2.addChild( grandchild3 );
+		root.addChild( child2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( grandchild );
+		s.delete( grandchild2 );
+		s.delete( grandchild3 );
+		s.delete( child );
+		s.delete( child2 );
+		s.delete( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+	}
+
+	public void testMergeDeepTreeWithGeneratedId() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		NumberedNode grandchild = new NumberedNode( "grandchild" );
+		root.addChild( child );
+		child.addChild( grandchild );
+		root = ( NumberedNode ) s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		child = ( NumberedNode ) root.getChildren().iterator().next();
+		grandchild = ( NumberedNode ) child.getChildren().iterator().next();
+		grandchild.setDescription( "the grand child" );
+		NumberedNode grandchild2 = new NumberedNode( "grandchild2" );
+		child.addChild( grandchild2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( NumberedNode ) s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 1 );
+		clearCounts();
+
+		getSessions().evict( NumberedNode.class );
+
+		NumberedNode child2 = new NumberedNode( "child2" );
+		NumberedNode grandchild3 = new NumberedNode( "grandchild3" );
+		child2.addChild( grandchild3 );
+		root.addChild( child2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( NumberedNode ) s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.createQuery( "delete from NumberedNode where name like 'grand%'" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode where name like 'child%'" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+	}
+
+	public void testMergeTree() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		root.addChild( child );
+		s.persist( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		child = ( Node ) root.getChildren().iterator().next();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		clearCounts();
+
+		root.setDescription( "The root node" );
+		child.setDescription( "The child node" );
+
+		Node secondChild = new Node( "second child" );
+
+		root.addChild( secondChild );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.merge( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 2 );
+
+		cleanup();
+	}
+
+	public void testMergeTreeWithGeneratedId() throws Exception {
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.persist( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		child = ( NumberedNode ) root.getChildren().iterator().next();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		clearCounts();
+
+		root.setDescription( "The root node" );
+		child.setDescription( "The child node" );
+
+		NumberedNode secondChild = new NumberedNode( "second child" );
+
+		root.addChild( secondChild );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.merge( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 2 );
+
+		cleanup();
+	}
+
+	public void testMergeManaged() throws Exception {
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		s.persist( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		NumberedNode child = new NumberedNode( "child" );
+		root = ( NumberedNode ) s.merge( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		root.addChild( child );
+		assertSame( root, s.merge( root ) );
+		Object mergedChild = root.getChildren().iterator().next();
+		assertNotSame( mergedChild, child );
+		assertTrue( s.contains( mergedChild ) );
+		assertFalse( s.contains( child ) );
+		assertEquals( root.getChildren().size(), 1 );
+		assertTrue( root.getChildren().contains( mergedChild ) );
+		//assertNotSame( mergedChild, s.merge(child) ); //yucky :(
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		mergedChild = root.getChildren().iterator().next();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 0 );
+
+		assertEquals( root.getChildren().size(), 1 );
+		assertTrue( root.getChildren().contains( mergedChild ) );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+				new Long( 2 )
+		);
+
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testMergeManagedUninitializedCollection() throws Exception {
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		root.addChild( new NumberedNode( "child" ) );
+		s.persist( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		NumberedNode newRoot = new NumberedNode( "root" );
+		newRoot.setId( root.getId() );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( NumberedNode ) s.get( NumberedNode.class, root.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		Set managedChildren = root.getChildren();
+		assertFalse( Hibernate.isInitialized( managedChildren ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		managedChildren = root.getChildren();
+		newRoot.setChildren( managedChildren );
+		assertSame( root, s.merge( newRoot ) );
+		assertSame( managedChildren, root.getChildren() );
+		assertFalse( Hibernate.isInitialized( managedChildren ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 );
+		assertDeleteCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+				new Long( 2 )
+		);
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testMergeManagedInitializedCollection() throws Exception {
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		root.addChild( new NumberedNode( "child" ) );
+		s.persist( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		NumberedNode newRoot = new NumberedNode( "root" );
+		newRoot.setId( root.getId() );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( NumberedNode ) s.get( NumberedNode.class, root.getId() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		Set managedChildren = root.getChildren();
+		Hibernate.initialize( managedChildren );
+		assertTrue( Hibernate.isInitialized( managedChildren ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		managedChildren = root.getChildren();
+		newRoot.setChildren( managedChildren );
+		assertSame( root, s.merge( newRoot ) );
+		assertSame( managedChildren, root.getChildren() );
+		assertTrue( Hibernate.isInitialized( managedChildren ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 );
+		assertDeleteCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+				new Long( 2 )
+		);
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testRecursiveMergeTransient() throws Exception {
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Employer jboss = new Employer();
+		Employee gavin = new Employee();
+		jboss.setEmployees( new ArrayList() );
+		jboss.getEmployees().add( gavin );
+		s.merge( jboss );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		s.flush();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		jboss = ( Employer ) s.createQuery( "from Employer e join fetch e.employees" ).uniqueResult();
+		assertTrue( Hibernate.isInitialized( jboss.getEmployees() ) );
+		assertEquals( 1, jboss.getEmployees().size() );
+		s.clear();
+		s.merge( jboss.getEmployees().iterator().next() );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testDeleteAndMerge() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Employer jboss = new Employer();
+		s.persist( jboss );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		Employer otherJboss;
+		otherJboss = ( Employer ) s.get( Employer.class, jboss.getId() );
+		s.delete( otherJboss );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		jboss.setVers( new Integer( 1 ) );
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.merge( jboss );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	public void testMergeManyToManyWithCollectionDeference() throws Exception {
+		// setup base data...
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Competition competition = new Competition();
+		competition.getCompetitors().add( new Competitor( "Name" ) );
+		competition.getCompetitors().add( new Competitor() );
+		competition.getCompetitors().add( new Competitor() );
+		s.persist( competition );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		// the competition graph is now detached:
+		//   1) create a new List reference to represent the competitors
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		List newComp = new ArrayList();
+		Competitor originalCompetitor = ( Competitor ) competition.getCompetitors().get( 0 );
+		originalCompetitor.setName( "Name2" );
+		newComp.add( originalCompetitor );
+		newComp.add( new Competitor() );
+		//   2) set that new List reference unto the Competition reference
+		competition.setCompetitors( newComp );
+		//   3) attempt the merge
+		Competition competition2 = ( Competition ) s.merge( competition );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		Competition competition2copy = ( Competition ) getOldToNewEntityRefMap().get( competition2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertFalse( competition == competition2 );
+		assertFalse( competition2 == competition2copy );
+		assertFalse( competition.getCompetitors() == competition2.getCompetitors() );
+		assertEquals( 2, competition2.getCompetitors().size() );
+		assertEquals( 2, competition2copy.getCompetitors().size() );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		competition = ( Competition ) s.get( Competition.class, competition.getId() );
+		assertEquals( 2, competition.getCompetitors().size() );
+		s.delete( competition );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		cleanup();
+	}
+
+	private void cleanup() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		s.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+
+		s.createQuery( "delete from Node where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from Node" ).executeUpdate();
+
+		s.createQuery( "delete from VersionedEntity where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from VersionedEntity" ).executeUpdate();
+		s.createQuery( "delete from TimestampedEntity" ).executeUpdate();
+
+		s.createQuery( "delete from Competitor" ).executeUpdate();
+		s.createQuery( "delete from Competition" ).executeUpdate();
+
+		Iterator itr = s.createQuery( "from Employer" ).list().iterator();
+		while ( itr.hasNext() ) {
+			final Employer employer = ( Employer ) itr.next();
+			s.delete( employer );
+		}
+
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+}
+


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/MergeTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.hbm.xml	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,51 @@
+<?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.nonflushedchanges">
+
+    <class name="Node" polymorphism="explicit">
+        <id name="name">
+            <generator class="assigned"/>
+        </id>
+        <property name="description"/>
+        <many-to-one name="parent"/>
+        <property name="created" not-null="true"/>
+        <set name="children"
+             inverse="true"
+             cascade="persist,merge,save-update,evict">
+            <key column="parent"/>
+            <one-to-many class="Node"/>
+        </set>
+        <set name="cascadingChildren" inverse="false" cascade="persist,merge,save-update,evict,delete">
+            <key column="CASC_PARENT"/>
+            <one-to-many class="Node"/>
+        </set>
+    </class>
+
+    <class name="NumberedNode" polymorphism="explicit">
+        <id name="id" unsaved-value="0">
+            <generator class="native"/>
+        </id>
+        <property name="name">
+            <column name="name" index="iname" not-null="true"/>
+        </property>
+        <property name="description"/>
+        <property name="created" not-null="true"
+                  type="imm_date"/>
+        <many-to-one name="parent" class="NumberedNode"/>
+        <set name="children"
+             inverse="true"
+             cascade="persist,merge,save-update">
+            <key column="parent"/>
+            <one-to-many class="NumberedNode"/>
+        </set>
+    </class>
+
+</hibernate-mapping>
+


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,89 @@
+//$Id: Node.java 10759 2006-11-08 00:00:53Z steve.ebersole at jboss.com $
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.sql.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King, Gail Badner (adapted this from "ops" tests version)
+ */
+public class Node implements Serializable {
+
+	private String name;
+	private String description;
+	private Date created;
+	private Node parent;
+	private Set children = new HashSet();
+	private Set cascadingChildren = new HashSet();
+
+	public Node() {
+	}
+
+	public Node(String name) {
+		this.name = name;
+		created = generateCurrentDate();
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Date getCreated() {
+		return created;
+	}
+
+	public void setCreated(Date created) {
+		this.created = created;
+	}
+
+	public Node getParent() {
+		return parent;
+	}
+
+	public void setParent(Node parent) {
+		this.parent = parent;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+
+	public Node addChild(Node child) {
+		children.add( child );
+		child.setParent( this );
+		return this;
+	}
+
+	public Set getCascadingChildren() {
+		return cascadingChildren;
+	}
+
+	public void setCascadingChildren(Set cascadingChildren) {
+		this.cascadingChildren = cascadingChildren;
+	}
+
+	private Date generateCurrentDate() {
+		// Note : done as java.sql.Date mainly to work around issue with
+		// MySQL and its lack of milli-second precision on its DATETIME
+		// and TIMESTAMP datatypes.
+		return new Date( new java.util.Date().getTime() );
+	}
+}


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Node.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/NumberedNode.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/NumberedNode.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/NumberedNode.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,83 @@
+//$Id: NumberedNode.java 7236 2005-06-20 03:19:34Z oneovthafew $
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King, Gail Badner (adapted this from "ops" tests version)
+ */
+public class NumberedNode implements Serializable {
+
+	private long id;
+	private String name;
+	private NumberedNode parent;
+	private Set children = new HashSet();
+	private String description;
+	private Date created;
+
+	public NumberedNode() {
+		super();
+	}
+
+	public NumberedNode(String name) {
+		this.name = name;
+		created = new Date();
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public NumberedNode getParent() {
+		return parent;
+	}
+
+	public void setParent(NumberedNode parent) {
+		this.parent = parent;
+	}
+
+	public NumberedNode addChild(NumberedNode child) {
+		children.add( child );
+		child.setParent( this );
+		return this;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Date getCreated() {
+		return created;
+	}
+
+	public void setCreated(Date created) {
+		this.created = created;
+	}
+}


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/NumberedNode.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OneToOne.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OneToOne.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OneToOne.hbm.xml	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ Mappings demonstrating bidirectional one-to-one mappings for testing
+ with various operations.
+
+ Person -> Address is modeled as a bidirectional one to one based on FK.
+ Person -> Details is modeled as a bidirectional one to one based on PK.
+-->
+
+<hibernate-mapping package="org.hibernate.test.nonflushedchanges">
+
+    <class name="Person" table="OPS_PERSON">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+        <one-to-one name="address" class="Address" property-ref="resident"/>
+        <one-to-one name="details" class="PersonalDetails" cascade="all"/>
+    </class>
+
+    <class name="Address" table="OPS_ADDRESS">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="streetAddress" column="STREET" type="string"/>
+        <property name="city" column="CITY" type="string"/>
+        <property name="country" column="CTRY" type="string"/>
+        <many-to-one name="resident" column="RESIDENT" class="Person"/>
+    </class>
+
+    <class name="PersonalDetails" table="OPS_PERS_DETAIL">
+        <id name="id" column="ID" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="somePersonalDetail" column="SOME_DETAIL" type="string"/>
+        <one-to-one name="person" class="Person" cascade="none" constrained="true"/>
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OptLockEntity.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OptLockEntity.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/OptLockEntity.hbm.xml	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,36 @@
+<?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.nonflushedchanges">
+
+    <class name="VersionedEntity" table="V_ENTITY">
+        <id name="id" column="ID" type="string">
+            <generator class="assigned"/>
+        </id>
+        <version name="version" column="VERS" type="long"/>
+        <property name="name" column="NAME" type="string"/>
+        <many-to-one name="parent" class="VersionedEntity"/>
+        <set name="children"
+             inverse="true"
+             cascade="persist,merge,save-update,evict,delete">
+            <key column="parent"/>
+            <one-to-many class="VersionedEntity"/>
+        </set>
+    </class>
+
+    <class name="TimestampedEntity" table="T_ENTITY">
+        <id name="id" column="ID" type="string">
+            <generator class="assigned"/>
+        </id>
+        <timestamp name="timestamp" column="TS"/>
+        <property name="name" column="NAME" type="string"/>
+    </class>
+
+</hibernate-mapping>
+

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Person.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Person.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/Person.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,54 @@
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public class Person implements Serializable {
+	private Long id;
+	private String name;
+	private Address address;
+	private PersonalDetails details;
+
+	public Person() {
+	}
+
+	public Person(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 Address getAddress() {
+		return address;
+	}
+
+	public void setAddress(Address address) {
+		this.address = address;
+	}
+
+	public PersonalDetails getDetails() {
+		return details;
+	}
+
+	public void setDetails(PersonalDetails details) {
+		this.details = details;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/PersonalDetails.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/PersonalDetails.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/PersonalDetails.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,47 @@
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public class PersonalDetails implements Serializable {
+	private Long id;
+	private String somePersonalDetail;
+	private Person person;
+
+	public PersonalDetails() {
+	}
+
+	public PersonalDetails(String somePersonalDetail, Person person) {
+		this.somePersonalDetail = somePersonalDetail;
+		this.person = person;
+		person.setDetails( this );
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getSomePersonalDetail() {
+		return somePersonalDetail;
+	}
+
+	public void setSomePersonalDetail(String somePersonalDetail) {
+		this.somePersonalDetail = somePersonalDetail;
+	}
+
+	public Person getPerson() {
+		return person;
+	}
+
+	public void setPerson(Person person) {
+		this.person = person;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/SaveOrUpdateTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/SaveOrUpdateTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/SaveOrUpdateTest.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,492 @@
+//$Id: SaveOrUpdateTest.java 10977 2006-12-12 23:28:04Z steve.ebersole at jboss.com $
+package org.hibernate.test.nonflushedchanges;
+
+import junit.framework.Test;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Projections;
+import org.hibernate.intercept.FieldInterceptionHelper;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+
+/**
+ * @author Gavin King, Gail Badner (adapted this from "ops" tests version)
+ */
+public class SaveOrUpdateTest extends AbstractOperationTestCase {
+
+	public SaveOrUpdateTest(String str) {
+		super( str );
+	}
+
+	public void testSaveOrUpdateDeepTree() throws Exception {
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		Node grandchild = new Node( "grandchild" );
+		root.addChild( child );
+		child.addChild( grandchild );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		child = ( Node ) getOldToNewEntityRefMap().get( child );
+		grandchild = ( Node ) getOldToNewEntityRefMap().get( grandchild );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		grandchild.setDescription( "the grand child" );
+		Node grandchild2 = new Node( "grandchild2" );
+		child.addChild( grandchild2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 1 );
+		clearCounts();
+
+		Node child2 = new Node( "child2" );
+		Node grandchild3 = new Node( "grandchild3" );
+		child2.addChild( grandchild3 );
+		root.addChild( child2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( grandchild );
+		s.delete( grandchild2 );
+		s.delete( grandchild3 );
+		s.delete( child );
+		s.delete( child2 );
+		s.delete( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testSaveOrUpdateDeepTreeWithGeneratedId() throws Exception {
+		boolean instrumented = FieldInterceptionHelper.isInstrumented( new NumberedNode() );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		NumberedNode grandchild = new NumberedNode( "grandchild" );
+		root.addChild( child );
+		child.addChild( grandchild );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		child = ( NumberedNode ) getOldToNewEntityRefMap().get( child );
+		grandchild = ( NumberedNode ) getOldToNewEntityRefMap().get( grandchild );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 3 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		child = ( NumberedNode ) root.getChildren().iterator().next();
+		grandchild = ( NumberedNode ) child.getChildren().iterator().next();
+		grandchild.setDescription( "the grand child" );
+		NumberedNode grandchild2 = new NumberedNode( "grandchild2" );
+		child.addChild( grandchild2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( instrumented ? 1 : 3 );
+		clearCounts();
+
+		NumberedNode child2 = new NumberedNode( "child2" );
+		NumberedNode grandchild3 = new NumberedNode( "grandchild3" );
+		child2.addChild( grandchild3 );
+		root.addChild( child2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		assertUpdateCount( instrumented ? 0 : 4 );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.createQuery( "delete from NumberedNode where name like 'grand%'" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode where name like 'child%'" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testSaveOrUpdateTree() throws Exception {
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node root = new Node( "root" );
+		Node child = new Node( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		child = ( Node ) getOldToNewEntityRefMap().get( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		clearCounts();
+
+		root.setDescription( "The root node" );
+		child.setDescription( "The child node" );
+
+		Node secondChild = new Node( "second child" );
+
+		root.addChild( secondChild );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.createQuery( "delete from Node where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from Node" ).executeUpdate();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testSaveOrUpdateTreeWithGeneratedId() throws Exception {
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		child = ( NumberedNode ) getOldToNewEntityRefMap().get( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 2 );
+		clearCounts();
+
+		root.setDescription( "The root node" );
+		child.setDescription( "The child node" );
+
+		NumberedNode secondChild = new NumberedNode( "second child" );
+
+		root.addChild( secondChild );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 2 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
+		s.createQuery( "delete from NumberedNode" ).executeUpdate();
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testSaveOrUpdateManaged() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( NumberedNode ) s.get( NumberedNode.class, root.getId() );
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		assertNull( getOldToNewEntityRefMap().get( child ) );
+		s.flush();
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		child = ( NumberedNode ) getOldToNewEntityRefMap().get( child );
+		child = ( NumberedNode ) root.getChildren().iterator().next();
+		assertTrue( s.contains( child ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		child = ( NumberedNode ) getOldToNewEntityRefMap().get( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertTrue( root.getChildren().contains( child ) );
+		assertEquals( root.getChildren().size(), 1 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+				new Long( 2 )
+		);
+		s.delete( root );
+		s.delete( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+
+	public void testSaveOrUpdateGot() throws Exception {
+		boolean instrumented = FieldInterceptionHelper.isInstrumented( new NumberedNode() );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		NumberedNode root = new NumberedNode( "root" );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( instrumented ? 0 : 1 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( NumberedNode ) s.get( NumberedNode.class, new Long( root.getId() ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		Hibernate.initialize( root.getChildren() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		NumberedNode child = new NumberedNode( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( NumberedNode ) getOldToNewEntityRefMap().get( root );
+		assertTrue( Hibernate.isInitialized( root.getChildren() ) );
+		child = ( NumberedNode ) root.getChildren().iterator().next();
+		assertTrue( s.contains( child ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( instrumented ? 0 : 1 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		assertEquals(
+				s.createCriteria( NumberedNode.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+				new Long( 2 )
+		);
+		s.delete( root );
+		s.delete( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testSaveOrUpdateGotWithMutableProp() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node root = new Node( "root" );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		assertUpdateCount( 0 );
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 0 );
+		assertUpdateCount( 0 );
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		root = ( Node ) s.get( Node.class, "root" );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		Hibernate.initialize( root.getChildren() );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		clearCounts();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		Node child = new Node( "child" );
+		root.addChild( child );
+		s.saveOrUpdate( root );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		child = ( Node ) root.getChildren().iterator().next();
+		assertTrue( s.contains( child ) );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		root = ( Node ) getOldToNewEntityRefMap().get( root );
+		child = ( Node ) getOldToNewEntityRefMap().get( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		assertInsertCount( 1 );
+		//assertUpdateCount( 1 ); //note: will fail here if no second-level cache
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		assertEquals(
+				s.createCriteria( Node.class )
+						.setProjection( Projections.rowCount() )
+						.uniqueResult(),
+				new Long( 2 )
+		);
+		s.delete( root );
+		s.delete( child );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void testEvictThenSaveOrUpdate() throws Exception {
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s = openSession();
+		Node parent = new Node( "1:parent" );
+		Node child = new Node( "2:child" );
+		Node grandchild = new Node( "3:grandchild" );
+		parent.addChild( child );
+		child.addChild( grandchild );
+		s.saveOrUpdate( parent );
+		s = applyNonFlushedChangesToNewSessionCloseOldSession( s );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s1 = openSession();
+		child = ( Node ) s1.load( Node.class, "2:child" );
+		s1 = applyNonFlushedChangesToNewSessionCloseOldSession( s1 );
+		child = ( Node ) getOldToNewEntityRefMap().get( child );
+		assertTrue( s1.contains( child ) );
+		assertFalse( Hibernate.isInitialized( child ) );
+		assertTrue( s1.contains( child.getParent() ) );
+		assertTrue( Hibernate.isInitialized( child ) );
+		assertFalse( Hibernate.isInitialized( child.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( child.getParent() ) );
+		assertTrue( s1.contains( child ) );
+		s1 = applyNonFlushedChangesToNewSessionCloseOldSession( s1 );
+		// child is an initialized proxy; after serialization, it is
+		// the proxy is replaced by its implementation
+		// TODO: find out if this is how this should work...
+		child = ( Node ) getOldToNewEntityRefMap().get(
+				( ( HibernateProxy ) child ).getHibernateLazyInitializer().getImplementation()
+		);
+		s1.evict( child );
+		assertFalse( s1.contains( child ) );
+		assertTrue( s1.contains( child.getParent() ) );
+
+		javax.transaction.Transaction tx1 = SimpleJtaTransactionManagerImpl.getInstance().suspend();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		Session s2 = openSession();
+		s2.saveOrUpdate( child );
+		s2 = applyNonFlushedChangesToNewSessionCloseOldSession( s2 );
+		child = ( Node ) getOldToNewEntityRefMap().get( child );
+		assertTrue( s2.contains( child ) );
+		assertFalse( s1.contains( child ) );
+		assertTrue( s2.contains( child.getParent() ) );
+		assertFalse( s1.contains( child.getParent() ) );
+		assertFalse( Hibernate.isInitialized( child.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( child.getParent() ) );
+		assertEquals( 1, child.getChildren().size() );
+		assertEquals( "1:parent", child.getParent().getName() );
+		assertTrue( Hibernate.isInitialized( child.getChildren() ) );
+		assertFalse( Hibernate.isInitialized( child.getParent() ) );
+		assertNull( child.getParent().getDescription() );
+		assertTrue( Hibernate.isInitialized( child.getParent() ) );
+		s1 = applyNonFlushedChangesToNewSessionCloseOldSession( s1 );
+		s2 = applyNonFlushedChangesToNewSessionCloseOldSession( s2 );
+
+		javax.transaction.Transaction tx2 = SimpleJtaTransactionManagerImpl.getInstance().suspend();
+		SimpleJtaTransactionManagerImpl.getInstance().resume( tx1 );
+		tx1.commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().resume( tx2 );
+		tx2.commit();
+
+		SimpleJtaTransactionManagerImpl.getInstance().begin();
+		s = openSession();
+		s.delete( s.get( Node.class, "3:grandchild" ) );
+		s.delete( s.get( Node.class, "2:child" ) );
+		s.delete( s.get( Node.class, "1:parent" ) );
+		SimpleJtaTransactionManagerImpl.getInstance().commit();
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+		cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "nonflushedchanges/Node.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( SaveOrUpdateTest.class );
+	}
+
+}
+


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/SaveOrUpdateTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/TimestampedEntity.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/TimestampedEntity.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/TimestampedEntity.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,48 @@
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * todo: describe TimestampedEntity
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public class TimestampedEntity implements Serializable {
+	private String id;
+	private String name;
+	private Date timestamp;
+
+	public TimestampedEntity() {
+	}
+
+	public TimestampedEntity(String id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Date getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Date timestamp) {
+		this.timestamp = timestamp;
+	}
+}
+

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/VersionedEntity.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/VersionedEntity.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/nonflushedchanges/VersionedEntity.java	2009-11-17 23:17:25 UTC (rev 17998)
@@ -0,0 +1,67 @@
+package org.hibernate.test.nonflushedchanges;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * VersionedEntity
+ *
+ * @author Steve Ebersole, Gail Badner (adapted this from "ops" tests version)
+ */
+public class VersionedEntity implements Serializable {
+	private String id;
+	private String name;
+	private long version;
+
+	private VersionedEntity parent;
+	private Set children = new HashSet();
+
+	public VersionedEntity() {
+	}
+
+	public VersionedEntity(String id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public long getVersion() {
+		return version;
+	}
+
+	public void setVersion(long version) {
+		this.version = version;
+	}
+
+	public VersionedEntity getParent() {
+		return parent;
+	}
+
+	public void setParent(VersionedEntity parent) {
+		this.parent = parent;
+	}
+
+	public Set getChildren() {
+		return children;
+	}
+
+	public void setChildren(Set children) {
+		this.children = children;
+	}
+}



More information about the hibernate-commits mailing list