HHH-3282 : DB2Dialect#supportsLobValueChangePropogation == false
git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@14660 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
e94b243e72
commit
c5cee56f1e
|
@ -55,7 +55,7 @@
|
||||||
The methods on <literal>Session</literal> are: <literal>enableFilter(String filterName)</literal>,
|
The methods on <literal>Session</literal> are: <literal>enableFilter(String filterName)</literal>,
|
||||||
<literal>getEnabledFilter(String filterName)</literal>, and <literal>disableFilter(String filterName)</literal>.
|
<literal>getEnabledFilter(String filterName)</literal>, and <literal>disableFilter(String filterName)</literal>.
|
||||||
By default, filters are <emphasis>not</emphasis> enabled for a given session; they must be explcitly
|
By default, filters are <emphasis>not</emphasis> enabled for a given session; they must be explcitly
|
||||||
enabled through use of the <literal>Session.enabledFilter()</literal> method, which returns an
|
enabled through use of the <literal>Session.enableFilter()</literal> method, which returns an
|
||||||
instance of the <literal>Filter</literal> interface. Using the simple filter defined above, this
|
instance of the <literal>Filter</literal> interface. Using the simple filter defined above, this
|
||||||
would look like:
|
would look like:
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -51,6 +51,7 @@ public class QueryKey implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
|
if ( !( other instanceof QueryKey ) ) return false;
|
||||||
QueryKey that = (QueryKey) other;
|
QueryKey that = (QueryKey) other;
|
||||||
if ( !sqlQueryString.equals(that.sqlQueryString) ) return false;
|
if ( !sqlQueryString.equals(that.sqlQueryString) ) return false;
|
||||||
if ( !EqualsHelper.equals(firstRow, that.firstRow) || !EqualsHelper.equals(maxRows, that.maxRows) ) return false;
|
if ( !EqualsHelper.equals(firstRow, that.firstRow) || !EqualsHelper.equals(maxRows, that.maxRows) ) return false;
|
||||||
|
|
|
@ -362,4 +362,8 @@ public class DB2Dialect extends Dialect {
|
||||||
public boolean supportsEmptyInList() {
|
public boolean supportsEmptyInList() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsLobValueChangePropogation() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,27 @@
|
||||||
package org.hibernate.event.def;
|
package org.hibernate.event.def;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.ObjectDeletedException;
|
import org.hibernate.ObjectDeletedException;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
|
import org.hibernate.TransientObjectException;
|
||||||
import org.hibernate.WrongClassException;
|
import org.hibernate.WrongClassException;
|
||||||
import org.hibernate.engine.Cascade;
|
import org.hibernate.engine.Cascade;
|
||||||
import org.hibernate.engine.CascadingAction;
|
import org.hibernate.engine.CascadingAction;
|
||||||
|
import org.hibernate.engine.EntityEntry;
|
||||||
|
import org.hibernate.engine.EntityKey;
|
||||||
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
import org.hibernate.engine.Status;
|
||||||
import org.hibernate.event.EventSource;
|
import org.hibernate.event.EventSource;
|
||||||
import org.hibernate.event.MergeEvent;
|
import org.hibernate.event.MergeEvent;
|
||||||
import org.hibernate.event.MergeEventListener;
|
import org.hibernate.event.MergeEventListener;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
|
||||||
import org.hibernate.engine.EntityEntry;
|
|
||||||
import org.hibernate.engine.EntityKey;
|
|
||||||
import org.hibernate.intercept.FieldInterceptionHelper;
|
import org.hibernate.intercept.FieldInterceptionHelper;
|
||||||
import org.hibernate.intercept.FieldInterceptor;
|
import org.hibernate.intercept.FieldInterceptor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -43,14 +47,33 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener
|
||||||
return IdentityMap.invert( (Map) anything );
|
return IdentityMap.invert( (Map) anything );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the given merge event.
|
* Handle the given merge event.
|
||||||
*
|
*
|
||||||
* @param event The merge event to be handled.
|
* @param event The merge event to be handled.
|
||||||
* @throws HibernateException
|
* @throws HibernateException
|
||||||
*/
|
*/
|
||||||
public void onMerge(MergeEvent event) throws HibernateException {
|
public void onMerge(MergeEvent event) throws HibernateException {
|
||||||
onMerge( event, IdentityMap.instantiate(10) );
|
Map copyCache = IdentityMap.instantiate(10);
|
||||||
|
onMerge( event, copyCache );
|
||||||
|
for ( Iterator it=copyCache.values().iterator(); it.hasNext(); ) {
|
||||||
|
Object entity = it.next();
|
||||||
|
if ( entity instanceof HibernateProxy ) {
|
||||||
|
entity = ( (HibernateProxy) entity ).getHibernateLazyInitializer().getImplementation();
|
||||||
|
}
|
||||||
|
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( entity );
|
||||||
|
if ( entry == null ) {
|
||||||
|
throw new TransientObjectException(
|
||||||
|
"object references an unsaved transient instance - save the transient instance before merging: " +
|
||||||
|
event.getSession().guessEntityName( entity )
|
||||||
|
);
|
||||||
|
// TODO: cache the entity name somewhere so that it is available to this exception
|
||||||
|
// entity name will not be available for non-POJO entities
|
||||||
|
}
|
||||||
|
if ( entry.getStatus() != Status.MANAGED ) {
|
||||||
|
throw new AssertionFailure( "Merged entity does not have status set to MANAGED; "+entry+" status="+entry.getStatus() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,7 +105,8 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener
|
||||||
entity = original;
|
entity = original;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( copyCache.containsKey(entity) ) {
|
if ( copyCache.containsKey(entity) &&
|
||||||
|
source.getContextEntityIdentifier( copyCache.get( entity ) ) != null ) {
|
||||||
log.trace("already merged");
|
log.trace("already merged");
|
||||||
event.setResult(entity);
|
event.setResult(entity);
|
||||||
}
|
}
|
||||||
|
@ -126,7 +150,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener
|
||||||
entityIsPersistent(event, copyCache);
|
entityIsPersistent(event, copyCache);
|
||||||
break;
|
break;
|
||||||
default: //DELETED
|
default: //DELETED
|
||||||
throw new ObjectDeletedException(
|
throw new ObjectDeletedException(
|
||||||
"deleted instance passed to merge",
|
"deleted instance passed to merge",
|
||||||
null,
|
null,
|
||||||
getLoggableName( event.getEntityName(), entity )
|
getLoggableName( event.getEntityName(), entity )
|
||||||
|
@ -137,7 +161,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void entityIsPersistent(MergeEvent event, Map copyCache) {
|
protected void entityIsPersistent(MergeEvent event, Map copyCache) {
|
||||||
log.trace("ignoring persistent instance");
|
log.trace("ignoring persistent instance");
|
||||||
|
|
||||||
|
@ -168,10 +192,15 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener
|
||||||
final Serializable id = persister.hasIdentifierProperty() ?
|
final Serializable id = persister.hasIdentifierProperty() ?
|
||||||
persister.getIdentifier( entity, source.getEntityMode() ) :
|
persister.getIdentifier( entity, source.getEntityMode() ) :
|
||||||
null;
|
null;
|
||||||
|
if ( copyCache.containsKey( entity ) ) {
|
||||||
final Object copy = persister.instantiate( id, source.getEntityMode() ); //TODO: should this be Session.instantiate(Persister, ...)?
|
persister.setIdentifier( copyCache.get( entity ), id, source.getEntityMode() );
|
||||||
copyCache.put(entity, copy); //before cascade!
|
}
|
||||||
|
else {
|
||||||
|
copyCache.put(entity, persister.instantiate( id, source.getEntityMode() ) ); //before cascade!
|
||||||
|
//TODO: should this be Session.instantiate(Persister, ...)?
|
||||||
|
}
|
||||||
|
final Object copy = copyCache.get( entity );
|
||||||
|
|
||||||
// cascade first, so that all unsaved objects get their
|
// cascade first, so that all unsaved objects get their
|
||||||
// copy created before we actually copy
|
// copy created before we actually copy
|
||||||
//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
|
//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
|
||||||
|
|
|
@ -250,13 +250,23 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
if ( original == target ) {
|
if ( original == target ) {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
Object id = getIdentifier( original, session );
|
if ( session.getContextEntityIdentifier( original ) == null &&
|
||||||
if ( id == null ) {
|
ForeignKeys.isTransient( associatedEntityName, original, Boolean.FALSE, session ) ) {
|
||||||
throw new AssertionFailure("cannot copy a reference to an object with a null id");
|
final Object copy = session.getFactory().getEntityPersister( associatedEntityName )
|
||||||
|
.instantiate( null, session.getEntityMode() );
|
||||||
|
//TODO: should this be Session.instantiate(Persister, ...)?
|
||||||
|
copyCache.put( original, copy );
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Object id = getIdentifier( original, session );
|
||||||
|
if ( id == null ) {
|
||||||
|
throw new AssertionFailure("non-transient entity has a null id");
|
||||||
|
}
|
||||||
|
id = getIdentifierOrUniqueKeyType( session.getFactory() )
|
||||||
|
.replace(id, null, session, owner, copyCache);
|
||||||
|
return resolve( id, session, owner );
|
||||||
}
|
}
|
||||||
id = getIdentifierOrUniqueKeyType( session.getFactory() )
|
|
||||||
.replace(id, null, session, owner, copyCache);
|
|
||||||
return resolve( id, session, owner );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
package org.hibernate.test.cascade;
|
package org.hibernate.test.cascade;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.TransientObjectException;
|
||||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:ovidiu@feodorov.com">Ovidiu Feodorov</a>
|
* @author <a href="mailto:ovidiu@feodorov.com">Ovidiu Feodorov</a>
|
||||||
|
@ -33,15 +32,23 @@ public class MultiPathCascadeTest extends FunctionalTestCase {
|
||||||
return new FunctionalTestClassTestSuite( MultiPathCascadeTest.class );
|
return new FunctionalTestClassTestSuite( MultiPathCascadeTest.class );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultiPathMergeDetachedFailureExpected() throws Exception
|
protected void cleanupTest() {
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.createQuery( "delete from A" );
|
||||||
|
s.createQuery( "delete from G" );
|
||||||
|
s.createQuery( "delete from H" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiPathMergeModifiedDetached() throws Exception
|
||||||
{
|
{
|
||||||
// persist a simple A in the database
|
// persist a simple A in the database
|
||||||
|
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
A a = new A();
|
A a = new A();
|
||||||
a.setData("Anna");
|
a.setData( "Anna" );
|
||||||
s.save(a);
|
s.save( a );
|
||||||
s.getTransaction().commit();
|
s.getTransaction().commit();
|
||||||
s.close();
|
s.close();
|
||||||
|
|
||||||
|
@ -50,22 +57,22 @@ public class MultiPathCascadeTest extends FunctionalTestCase {
|
||||||
|
|
||||||
s = openSession();
|
s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
s.merge(a);
|
a = ( A ) s.merge( a );
|
||||||
s.getTransaction().commit();
|
s.getTransaction().commit();
|
||||||
s.close();
|
s.close();
|
||||||
|
|
||||||
verifyModifications( a.getId() );
|
verifyModifications( a.getId() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultiPathUpdateDetached() throws Exception
|
public void testMultiPathMergeModifiedDetachedIntoProxy() throws Exception
|
||||||
{
|
{
|
||||||
// persist a simple A in the database
|
// persist a simple A in the database
|
||||||
|
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
A a = new A();
|
A a = new A();
|
||||||
a.setData("Anna");
|
a.setData( "Anna" );
|
||||||
s.save(a);
|
s.save( a );
|
||||||
s.getTransaction().commit();
|
s.getTransaction().commit();
|
||||||
s.close();
|
s.close();
|
||||||
|
|
||||||
|
@ -74,7 +81,33 @@ public class MultiPathCascadeTest extends FunctionalTestCase {
|
||||||
|
|
||||||
s = openSession();
|
s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
s.update(a);
|
A aLoaded = ( A ) s.load( A.class, new Long( a.getId() ) );
|
||||||
|
assertTrue( aLoaded instanceof HibernateProxy );
|
||||||
|
assertSame( aLoaded, s.merge( a ) );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
verifyModifications( a.getId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiPathUpdateModifiedDetached() throws Exception
|
||||||
|
{
|
||||||
|
// persist a simple A in the database
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
A a = new A();
|
||||||
|
a.setData( "Anna" );
|
||||||
|
s.save( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
// modify detached entity
|
||||||
|
modifyEntity( a );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.update( a );
|
||||||
s.getTransaction().commit();
|
s.getTransaction().commit();
|
||||||
s.close();
|
s.close();
|
||||||
|
|
||||||
|
@ -88,8 +121,8 @@ public class MultiPathCascadeTest extends FunctionalTestCase {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
A a = new A();
|
A a = new A();
|
||||||
a.setData("Anna");
|
a.setData( "Anna" );
|
||||||
s.save(a);
|
s.save( a );
|
||||||
s.getTransaction().commit();
|
s.getTransaction().commit();
|
||||||
s.close();
|
s.close();
|
||||||
|
|
||||||
|
@ -104,24 +137,168 @@ public class MultiPathCascadeTest extends FunctionalTestCase {
|
||||||
verifyModifications( a.getId() );
|
verifyModifications( a.getId() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMultiPathMergeNonCascadedTransientEntityInCollection() throws Exception
|
||||||
|
{
|
||||||
|
// persist a simple A in the database
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
A a = new A();
|
||||||
|
a.setData( "Anna" );
|
||||||
|
s.save( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
// modify detached entity
|
||||||
|
modifyEntity( a );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
a = ( A ) s.merge( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
verifyModifications( a.getId() );
|
||||||
|
|
||||||
|
// add a new (transient) G to collection in h
|
||||||
|
// there is no cascade from H to the collection, so this should fail when merged
|
||||||
|
assertEquals( 1, a.getHs().size() );
|
||||||
|
H h = ( H ) a.getHs().iterator().next();
|
||||||
|
G gNew = new G();
|
||||||
|
gNew.setData( "Gail" );
|
||||||
|
gNew.getHs().add( h );
|
||||||
|
h.getGs().add( gNew );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
try {
|
||||||
|
s.merge( a );
|
||||||
|
s.merge( h );
|
||||||
|
fail( "should have thrown TransientObjectException" );
|
||||||
|
}
|
||||||
|
catch ( TransientObjectException ex ) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiPathMergeNonCascadedTransientEntityInOneToOne() throws Exception
|
||||||
|
{
|
||||||
|
// persist a simple A in the database
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
A a = new A();
|
||||||
|
a.setData( "Anna" );
|
||||||
|
s.save( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
// modify detached entity
|
||||||
|
modifyEntity( a );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
a = ( A ) s.merge( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
verifyModifications( a.getId() );
|
||||||
|
|
||||||
|
// change the one-to-one association from g to be a new (transient) A
|
||||||
|
// there is no cascade from G to A, so this should fail when merged
|
||||||
|
G g = a.getG();
|
||||||
|
a.setG( null );
|
||||||
|
A aNew = new A();
|
||||||
|
aNew.setData( "Alice" );
|
||||||
|
g.setA( aNew );
|
||||||
|
aNew.setG( g );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
try {
|
||||||
|
s.merge( a );
|
||||||
|
s.merge( g );
|
||||||
|
fail( "should have thrown TransientObjectException" );
|
||||||
|
}
|
||||||
|
catch ( TransientObjectException ex ) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiPathMergeNonCascadedTransientEntityInManyToOne() throws Exception
|
||||||
|
{
|
||||||
|
// persist a simple A in the database
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
A a = new A();
|
||||||
|
a.setData( "Anna" );
|
||||||
|
s.save( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
// modify detached entity
|
||||||
|
modifyEntity( a );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
a = ( A ) s.merge( a );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
verifyModifications( a.getId() );
|
||||||
|
|
||||||
|
// change the many-to-one association from h to be a new (transient) A
|
||||||
|
// there is no cascade from H to A, so this should fail when merged
|
||||||
|
assertEquals( 1, a.getHs().size() );
|
||||||
|
H h = ( H ) a.getHs().iterator().next();
|
||||||
|
a.getHs().remove( h );
|
||||||
|
A aNew = new A();
|
||||||
|
aNew.setData( "Alice" );
|
||||||
|
aNew.addH( h );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
try {
|
||||||
|
s.merge( a );
|
||||||
|
s.merge( h );
|
||||||
|
fail( "should have thrown TransientObjectException" );
|
||||||
|
}
|
||||||
|
catch ( TransientObjectException ex ) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
private void modifyEntity(A a) {
|
private void modifyEntity(A a) {
|
||||||
// create a *circular* graph in detached entity
|
// create a *circular* graph in detached entity
|
||||||
a.setData("Anthony");
|
a.setData("Anthony");
|
||||||
|
|
||||||
G g = new G();
|
G g = new G();
|
||||||
g.setData("Giovanni");
|
g.setData( "Giovanni" );
|
||||||
|
|
||||||
H h = new H();
|
H h = new H();
|
||||||
h.setData("Hellen");
|
h.setData( "Hellen" );
|
||||||
|
|
||||||
a.setG(g);
|
a.setG( g );
|
||||||
g.setA(a);
|
g.setA( a );
|
||||||
|
|
||||||
a.getHs().add(h);
|
a.getHs().add( h );
|
||||||
h.setA(a);
|
h.setA( a );
|
||||||
|
|
||||||
g.getHs().add(h);
|
g.getHs().add( h );
|
||||||
h.getGs().add(g);
|
h.getGs().add( g );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyModifications(long aId) {
|
private void verifyModifications(long aId) {
|
||||||
|
@ -157,4 +334,4 @@ public class MultiPathCascadeTest extends FunctionalTestCase {
|
||||||
s.close();
|
s.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ package org.hibernate.test.ops;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
@ -561,6 +562,94 @@ public class MergeTest extends AbstractOperationTestCase {
|
||||||
// cleanup();
|
// cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMergeManagedUninitializedCollection() {
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
Transaction tx = s.beginTransaction();
|
||||||
|
NumberedNode root = new NumberedNode( "root" );
|
||||||
|
root.addChild( new NumberedNode( "child" ) );
|
||||||
|
s.persist(root);
|
||||||
|
tx.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
clearCounts();
|
||||||
|
|
||||||
|
NumberedNode newRoot = new NumberedNode( "root" );
|
||||||
|
newRoot.setId( root.getId() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
tx = s.beginTransaction();
|
||||||
|
root = ( NumberedNode ) s.get( NumberedNode.class, new Long( root.getId() ) );
|
||||||
|
Set managedChildren = root.getChildren();
|
||||||
|
assertFalse( Hibernate.isInitialized( managedChildren ) );
|
||||||
|
newRoot.setChildren( managedChildren );
|
||||||
|
assertSame( root, s.merge( newRoot ) );
|
||||||
|
assertSame( managedChildren, root.getChildren() );
|
||||||
|
assertFalse( Hibernate.isInitialized( managedChildren ) );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
assertInsertCount(0);
|
||||||
|
assertUpdateCount(0);
|
||||||
|
assertDeleteCount(0);
|
||||||
|
|
||||||
|
tx = s.beginTransaction();
|
||||||
|
assertEquals(
|
||||||
|
s.createCriteria(NumberedNode.class)
|
||||||
|
.setProjection( Projections.rowCount() )
|
||||||
|
.uniqueResult(),
|
||||||
|
new Integer(2)
|
||||||
|
);
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
// cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMergeManagedInitializedCollection() {
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
Transaction tx = s.beginTransaction();
|
||||||
|
NumberedNode root = new NumberedNode( "root" );
|
||||||
|
root.addChild( new NumberedNode( "child" ) );
|
||||||
|
s.persist(root);
|
||||||
|
tx.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
clearCounts();
|
||||||
|
|
||||||
|
NumberedNode newRoot = new NumberedNode( "root" );
|
||||||
|
newRoot.setId( root.getId() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
tx = s.beginTransaction();
|
||||||
|
root = ( NumberedNode ) s.get( NumberedNode.class, new Long( root.getId() ) );
|
||||||
|
Set managedChildren = root.getChildren();
|
||||||
|
Hibernate.initialize( managedChildren );
|
||||||
|
assertTrue( Hibernate.isInitialized( managedChildren ) );
|
||||||
|
newRoot.setChildren( managedChildren );
|
||||||
|
assertSame( root, s.merge( newRoot ) );
|
||||||
|
assertSame( managedChildren, root.getChildren() );
|
||||||
|
assertTrue( Hibernate.isInitialized( managedChildren ) );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
assertInsertCount(0);
|
||||||
|
assertUpdateCount(0);
|
||||||
|
assertDeleteCount(0);
|
||||||
|
|
||||||
|
tx = s.beginTransaction();
|
||||||
|
assertEquals(
|
||||||
|
s.createCriteria(NumberedNode.class)
|
||||||
|
.setProjection( Projections.rowCount() )
|
||||||
|
.uniqueResult(),
|
||||||
|
new Integer(2)
|
||||||
|
);
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
// cleanup();
|
||||||
|
}
|
||||||
public void testRecursiveMergeTransient() {
|
public void testRecursiveMergeTransient() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
Transaction tx = s.beginTransaction();
|
Transaction tx = s.beginTransaction();
|
||||||
|
|
Loading…
Reference in New Issue