HHH-7133 - NaturalIdLoadAccess not correctly working on mutable NaturalId's

This commit is contained in:
Steve Ebersole 2012-03-14 17:56:10 -05:00
parent 8ffdc614d7
commit ef41cdd6dd
3 changed files with 105 additions and 7 deletions

View File

@ -40,6 +40,7 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper;
/**
* Maintains a {@link org.hibernate.engine.spi.PersistenceContext}-level 2-way cross-reference (xref) between the
@ -67,6 +68,7 @@ public class NaturalIdXrefDelegate {
final Serializable pk,
Object[] naturalIdValues,
CachedNaturalIdValueSource valueSource) {
persister = locatePersisterForKey( persister );
validateNaturalId( persister, naturalIdValues );
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
@ -146,6 +148,10 @@ public class NaturalIdXrefDelegate {
}
}
protected EntityPersister locatePersisterForKey(EntityPersister persister) {
return persistenceContext.getSession().getFactory().getEntityPersister( persister.getRootEntityName() );
}
protected void validateNaturalId(EntityPersister persister, Object[] naturalIdValues) {
if ( !persister.hasNaturalIdentifier() ) {
throw new IllegalArgumentException( "Entity did not define a natrual-id" );
@ -156,6 +162,7 @@ public class NaturalIdXrefDelegate {
}
public void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] deletedNaturalIdValues) {
persister = locatePersisterForKey( persister );
validateNaturalId( persister, deletedNaturalIdValues );
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
@ -184,6 +191,7 @@ public class NaturalIdXrefDelegate {
}
public Object[] findCachedNaturalId(EntityPersister persister, Serializable pk) {
persister = locatePersisterForKey( persister );
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
if ( entityNaturalIdResolutionCache == null ) {
return null;
@ -198,6 +206,7 @@ public class NaturalIdXrefDelegate {
}
public Serializable findCachedNaturalIdResolution(EntityPersister persister, Object[] naturalIdValues) {
persister = locatePersisterForKey( persister );
validateNaturalId( persister, naturalIdValues );
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
@ -270,6 +279,7 @@ public class NaturalIdXrefDelegate {
private static class CachedNaturalId {
private final EntityPersister persister;
private final Object[] values;
private final Type[] naturalIdTypes;
private int hashCode;
public CachedNaturalId(EntityPersister persister, Object[] values) {
@ -277,10 +287,21 @@ public class NaturalIdXrefDelegate {
this.values = values;
final int prime = 31;
int result = 1;
result = prime * result + ( ( persister == null ) ? 0 : persister.hashCode() );
result = prime * result + Arrays.hashCode( values );
this.hashCode = result;
int hashCodeCalculation = 1;
hashCodeCalculation = prime * hashCodeCalculation + persister.hashCode();
final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties();
naturalIdTypes = new Type[ naturalIdPropertyIndexes.length ];
int i = 0;
for ( int naturalIdPropertyIndex : naturalIdPropertyIndexes ) {
final Type type = persister.getPropertyType( persister.getPropertyNames()[ naturalIdPropertyIndex ] );
naturalIdTypes[i] = type;
int elementHashCode = values[i] == null ? 0 :type.getHashCode( values[i], persister.getFactory() );
hashCodeCalculation = prime * hashCodeCalculation + elementHashCode;
i++;
}
this.hashCode = hashCodeCalculation;
}
public Object[] getValues() {
@ -305,8 +326,17 @@ public class NaturalIdXrefDelegate {
}
final CachedNaturalId other = (CachedNaturalId) obj;
return persister.equals( other.persister )
&& Arrays.equals( values, other.values );
return persister.equals( other.persister ) && areSame( values, other.values );
}
private boolean areSame(Object[] values, Object[] otherValues) {
// lengths have already been verified at this point
for ( int i = 0; i < naturalIdTypes.length; i++ ) {
if ( ! naturalIdTypes[i].isEqual( values[i], otherValues[i], persister.getFactory() ) ) {
return false;
}
}
return true;
}
}

View File

@ -29,6 +29,10 @@ import org.junit.Test;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
/**
* @author Steve Ebersole
*/
@ -57,5 +61,69 @@ public class InheritedNaturalIdTest extends BaseCoreFunctionalTestCase {
s.bySimpleNaturalId( User.class ).load( "steve" );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.delete( s.bySimpleNaturalId( User.class ).load( "steve" ) );
s.getTransaction().commit();
s.close();
}
@Test
public void testSubclassModifieablNaturalId() {
Session s = openSession();
s.beginTransaction();
s.save( new User( "steve" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
Principal p = (Principal) s.bySimpleNaturalId( Principal.class ).load( "steve" );
assertNotNull( p );
User u = (User) s.bySimpleNaturalId( User.class ).load( "steve" );
assertNotNull( u );
assertSame( p, u );
// change the natural id
u.setUid( "sebersole" );
s.flush();
// make sure we can no longer access the info based on the old natural id value
assertNull( s.bySimpleNaturalId( Principal.class ).load( "steve" ) );
assertNull( s.bySimpleNaturalId( User.class ).load( "steve" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.delete( u );
s.getTransaction().commit();
s.close();
}
@Test
public void testSubclassDeleteNaturalId() {
Session s = openSession();
s.beginTransaction();
s.save( new User( "steve" ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
Principal p = (Principal) s.bySimpleNaturalId( Principal.class ).load( "steve" );
assertNotNull( p );
s.delete( p );
s.flush();
// assertNull( s.bySimpleNaturalId( Principal.class ).load( "steve" ) );
assertNull( s.bySimpleNaturalId( User.class ).load( "steve" ) );
s.getTransaction().commit();
s.close();
}
}

View File

@ -63,7 +63,7 @@ public abstract class Principal {
this.id = id;
}
@NaturalId
@NaturalId(mutable=true)
public String getUid() {
return uid;
}