Skip to content

Commit

Permalink
HHH-7133 - NaturalIdLoadAccess not correctly working on mutable Natur…
Browse files Browse the repository at this point in the history
…alId's
  • Loading branch information
sebersole committed Mar 14, 2012
1 parent 8ffdc61 commit ef41cdd
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 7 deletions.
Expand Up @@ -40,6 +40,7 @@
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
Expand Down Expand Up @@ -67,6 +68,7 @@ public void cacheNaturalIdResolution(
final Serializable pk,
Object[] naturalIdValues,
CachedNaturalIdValueSource valueSource) {
persister = locatePersisterForKey( persister );
validateNaturalId( persister, naturalIdValues );

NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
Expand Down Expand Up @@ -146,6 +148,10 @@ public void doAfterTransactionCompletion(boolean success, SessionImplementor ses
}
}

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" );
Expand All @@ -156,6 +162,7 @@ protected void validateNaturalId(EntityPersister persister, Object[] naturalIdVa
}

public void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] deletedNaturalIdValues) {
persister = locatePersisterForKey( persister );
validateNaturalId( persister, deletedNaturalIdValues );

NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
Expand Down Expand Up @@ -184,6 +191,7 @@ public void evictNaturalIdResolution(EntityPersister persister, final Serializab
}

public Object[] findCachedNaturalId(EntityPersister persister, Serializable pk) {
persister = locatePersisterForKey( persister );
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
if ( entityNaturalIdResolutionCache == null ) {
return null;
Expand All @@ -198,6 +206,7 @@ public Object[] findCachedNaturalId(EntityPersister persister, Serializable pk)
}

public Serializable findCachedNaturalIdResolution(EntityPersister persister, Object[] naturalIdValues) {
persister = locatePersisterForKey( persister );
validateNaturalId( persister, naturalIdValues );

NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
Expand Down Expand Up @@ -270,17 +279,29 @@ else if ( factory.getStatistics().isStatisticsEnabled() ) {
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) {
this.persister = persister;
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() {
Expand All @@ -305,8 +326,17 @@ public boolean equals(Object obj) {
}

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;
}
}

Expand Down
Expand Up @@ -29,6 +29,10 @@

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
*/
Expand Down Expand Up @@ -57,5 +61,69 @@ public void testIt() {
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();
}
}
Expand Up @@ -63,7 +63,7 @@ public void setId(Long id) {
this.id = id;
}

@NaturalId
@NaturalId(mutable=true)
public String getUid() {
return uid;
}
Expand Down

0 comments on commit ef41cdd

Please sign in to comment.