mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-09 12:44:49 +00:00
HHH-14409 : Internal format of natural-id values
At the moment, internally the value of a natural-id is always kept as an array. For simple natural-ids that means creating an unnecessary array to wrap the simple value. Change this to allow Object to allow for these simple values
This commit is contained in:
parent
0196911c8d
commit
3ecc2550df
@ -17,6 +17,7 @@
|
|||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.engine.spi.Status;
|
import org.hibernate.engine.spi.Status;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,13 +164,15 @@ public void afterDeserialize(SharedSessionContractImplementor session) {
|
|||||||
*/
|
*/
|
||||||
protected void handleNaturalIdPreSaveNotifications() {
|
protected void handleNaturalIdPreSaveNotifications() {
|
||||||
// before save, we need to add a local (transactional) natural id cross-reference
|
// before save, we need to add a local (transactional) natural id cross-reference
|
||||||
getSession().getPersistenceContextInternal().getNaturalIdHelper().manageLocalNaturalIdCrossReference(
|
final NaturalIdMapping naturalIdMapping = getPersister().getNaturalIdMapping();
|
||||||
getPersister(),
|
if ( naturalIdMapping != null ) {
|
||||||
getId(),
|
getSession().getPersistenceContextInternal().getNaturalIdHelper().manageLocalResolution(
|
||||||
state,
|
getId(),
|
||||||
null,
|
naturalIdMapping.extractNaturalIdValues( state, getSession() ),
|
||||||
CachedNaturalIdValueSource.INSERT
|
getPersister(),
|
||||||
);
|
CachedNaturalIdValueSource.INSERT
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,23 +181,29 @@ protected void handleNaturalIdPreSaveNotifications() {
|
|||||||
* @param generatedId The generated entity identifier
|
* @param generatedId The generated entity identifier
|
||||||
*/
|
*/
|
||||||
public void handleNaturalIdPostSaveNotifications(Object generatedId) {
|
public void handleNaturalIdPostSaveNotifications(Object generatedId) {
|
||||||
|
final NaturalIdMapping naturalIdMapping = getPersister().getNaturalIdMapping();
|
||||||
|
if ( naturalIdMapping == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object naturalIdValues = naturalIdMapping.extractNaturalIdValues( state, getSession() );
|
||||||
|
|
||||||
final PersistenceContext.NaturalIdHelper naturalIdHelper = getSession().getPersistenceContextInternal().getNaturalIdHelper();
|
final PersistenceContext.NaturalIdHelper naturalIdHelper = getSession().getPersistenceContextInternal().getNaturalIdHelper();
|
||||||
if ( isEarlyInsert() ) {
|
if ( isEarlyInsert() ) {
|
||||||
// with early insert, we still need to add a local (transactional) natural id cross-reference
|
// with early insert, we still need to add a local (transactional) natural id cross-reference
|
||||||
naturalIdHelper.manageLocalNaturalIdCrossReference(
|
naturalIdHelper.manageLocalResolution(
|
||||||
getPersister(),
|
|
||||||
generatedId,
|
generatedId,
|
||||||
state,
|
naturalIdValues,
|
||||||
null,
|
getPersister(),
|
||||||
CachedNaturalIdValueSource.INSERT
|
CachedNaturalIdValueSource.INSERT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// after save, we need to manage the shared cache entries
|
// after save, we need to manage the shared cache entries
|
||||||
naturalIdHelper.manageSharedNaturalIdCrossReference(
|
naturalIdHelper.manageSharedResolution(
|
||||||
getPersister(),
|
|
||||||
generatedId,
|
generatedId,
|
||||||
state,
|
naturalIdValues,
|
||||||
null,
|
null,
|
||||||
|
getPersister(),
|
||||||
CachedNaturalIdValueSource.INSERT
|
CachedNaturalIdValueSource.INSERT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
import org.hibernate.event.spi.PostDeleteEventListener;
|
import org.hibernate.event.spi.PostDeleteEventListener;
|
||||||
import org.hibernate.event.spi.PreDeleteEvent;
|
import org.hibernate.event.spi.PreDeleteEvent;
|
||||||
import org.hibernate.event.spi.PreDeleteEventListener;
|
import org.hibernate.event.spi.PreDeleteEventListener;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
@ -33,7 +34,9 @@ public class EntityDeleteAction extends EntityAction {
|
|||||||
private final Object[] state;
|
private final Object[] state;
|
||||||
|
|
||||||
private SoftLock lock;
|
private SoftLock lock;
|
||||||
private Object[] naturalIdValues;
|
|
||||||
|
private final NaturalIdMapping naturalIdMapping;
|
||||||
|
private Object naturalIdValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an EntityDeleteAction.
|
* Constructs an EntityDeleteAction.
|
||||||
@ -58,12 +61,15 @@ public EntityDeleteAction(
|
|||||||
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
|
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
|
||||||
// before remove we need to remove the local (transactional) natural id cross-reference
|
this.naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdHelper().removeLocalNaturalIdCrossReference(
|
|
||||||
getPersister(),
|
if ( naturalIdMapping != null ) {
|
||||||
getId(),
|
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdHelper().removeLocalResolution(
|
||||||
state
|
getPersister(),
|
||||||
);
|
getId(),
|
||||||
|
naturalIdMapping.extractNaturalIdValues( state, session )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getVersion() {
|
public Object getVersion() {
|
||||||
@ -78,7 +84,7 @@ public Object[] getState() {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object[] getNaturalIdValues() {
|
protected Object getNaturalIdValues() {
|
||||||
return naturalIdValues;
|
return naturalIdValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +145,7 @@ public void execute() throws HibernateException {
|
|||||||
persister.getCacheAccessStrategy().remove( session, ck);
|
persister.getCacheAccessStrategy().remove( session, ck);
|
||||||
}
|
}
|
||||||
|
|
||||||
persistenceContext.getNaturalIdHelper().removeSharedNaturalIdCrossReference( persister, id, naturalIdValues );
|
persistenceContext.getNaturalIdHelper().removeSharedResolution( persister, id, naturalIdValues );
|
||||||
|
|
||||||
postDelete();
|
postDelete();
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
import org.hibernate.event.spi.PostUpdateEventListener;
|
import org.hibernate.event.spi.PostUpdateEventListener;
|
||||||
import org.hibernate.event.spi.PreUpdateEvent;
|
import org.hibernate.event.spi.PreUpdateEvent;
|
||||||
import org.hibernate.event.spi.PreUpdateEventListener;
|
import org.hibernate.event.spi.PreUpdateEventListener;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.stat.internal.StatsHelper;
|
import org.hibernate.stat.internal.StatsHelper;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
@ -42,11 +43,13 @@ public class EntityUpdateAction extends EntityAction {
|
|||||||
private final int[] dirtyFields;
|
private final int[] dirtyFields;
|
||||||
private final boolean hasDirtyCollection;
|
private final boolean hasDirtyCollection;
|
||||||
private final Object rowId;
|
private final Object rowId;
|
||||||
private final Object[] previousNaturalIdValues;
|
|
||||||
private Object nextVersion;
|
private Object nextVersion;
|
||||||
private Object cacheEntry;
|
private Object cacheEntry;
|
||||||
private SoftLock lock;
|
private SoftLock lock;
|
||||||
|
|
||||||
|
private final NaturalIdMapping naturalIdMapping;
|
||||||
|
private final Object previousNaturalIdValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an EntityUpdateAction
|
* Constructs an EntityUpdateAction
|
||||||
* @param id The entity identifier
|
* @param id The entity identifier
|
||||||
@ -82,24 +85,23 @@ public EntityUpdateAction(
|
|||||||
this.hasDirtyCollection = hasDirtyCollection;
|
this.hasDirtyCollection = hasDirtyCollection;
|
||||||
this.rowId = rowId;
|
this.rowId = rowId;
|
||||||
|
|
||||||
this.previousNaturalIdValues = determinePreviousNaturalIdValues( persister, id, previousState, session );
|
this.naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
session.getPersistenceContextInternal().getNaturalIdHelper().manageLocalNaturalIdCrossReference(
|
if ( naturalIdMapping == null ) {
|
||||||
persister,
|
previousNaturalIdValues = null;
|
||||||
id,
|
}
|
||||||
state,
|
else {
|
||||||
previousNaturalIdValues,
|
this.previousNaturalIdValues = determinePreviousNaturalIdValues( persister, id, previousState, session );
|
||||||
CachedNaturalIdValueSource.UPDATE
|
session.getPersistenceContextInternal().getNaturalIdHelper().manageLocalResolution(
|
||||||
);
|
id, state, persister,
|
||||||
|
CachedNaturalIdValueSource.UPDATE
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object[] determinePreviousNaturalIdValues(
|
private static Object determinePreviousNaturalIdValues(
|
||||||
EntityPersister persister,
|
EntityPersister persister,
|
||||||
Object id, Object[] previousState,
|
Object id, Object[] previousState,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
if ( ! persister.hasNaturalIdentifier() ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
if ( previousState != null ) {
|
if ( previousState != null ) {
|
||||||
return persistenceContext.getNaturalIdHelper().extractNaturalIdValues( previousState, persister );
|
return persistenceContext.getNaturalIdHelper().extractNaturalIdValues( previousState, persister );
|
||||||
@ -116,50 +118,10 @@ public Object[] getPreviousState() {
|
|||||||
return previousState;
|
return previousState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getPreviousVersion() {
|
|
||||||
return previousVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getNextVersion() {
|
|
||||||
return nextVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNextVersion(Object nextVersion) {
|
|
||||||
this.nextVersion = nextVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getDirtyFields() {
|
|
||||||
return dirtyFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasDirtyCollection() {
|
|
||||||
return hasDirtyCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getRowId() {
|
public Object getRowId() {
|
||||||
return rowId;
|
return rowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] getPreviousNaturalIdValues() {
|
|
||||||
return previousNaturalIdValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Object getCacheEntry() {
|
|
||||||
return cacheEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setCacheEntry(Object cacheEntry) {
|
|
||||||
this.cacheEntry = cacheEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected SoftLock getLock() {
|
|
||||||
return lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setLock(SoftLock lock) {
|
|
||||||
this.lock = lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws HibernateException {
|
public void execute() throws HibernateException {
|
||||||
final Object id = getId();
|
final Object id = getId();
|
||||||
@ -256,13 +218,15 @@ else if ( session.getCacheMode().isPutEnabled() ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getPersistenceContextInternal().getNaturalIdHelper().manageSharedNaturalIdCrossReference(
|
if ( naturalIdMapping != null ) {
|
||||||
persister,
|
session.getPersistenceContextInternal().getNaturalIdHelper().manageSharedResolution(
|
||||||
id,
|
id,
|
||||||
state,
|
naturalIdMapping.extractNaturalIdValues( state, session ),
|
||||||
previousNaturalIdValues,
|
naturalIdMapping.extractNaturalIdValues( previousState, session ),
|
||||||
CachedNaturalIdValueSource.UPDATE
|
persister,
|
||||||
);
|
CachedNaturalIdValueSource.UPDATE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
postUpdate();
|
postUpdate();
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public static Object staticCreateEntityKey(Object id, EntityPersister persister,
|
|||||||
return new CacheKeyImplementation( id, persister.getIdentifierType(), persister.getRootEntityName(), tenantIdentifier, factory );
|
return new CacheKeyImplementation( id, persister.getIdentifierType(), persister.getRootEntityName(), tenantIdentifier, factory );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object staticCreateNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
public static Object staticCreateNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||||
return new NaturalIdCacheKey( naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), persister.getRootEntityName(), session );
|
return new NaturalIdCacheKey( naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), persister.getRootEntityName(), session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ public static Object staticGetCollectionId(Object cacheKey) {
|
|||||||
return ((CacheKeyImplementation) cacheKey).getId();
|
return ((CacheKeyImplementation) cacheKey).getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] staticGetNaturalIdValues(Object cacheKey) {
|
public static Object staticGetNaturalIdValues(Object cacheKey) {
|
||||||
return ((NaturalIdCacheKey) cacheKey).getNaturalIdValues();
|
return ((NaturalIdCacheKey) cacheKey).getNaturalIdValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ public Object createEntityKey(Object id, EntityPersister persister, SessionFacto
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
public Object createNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||||
return staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
return staticCreateNaturalIdKey(naturalIdValues, persister, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ public Object getCollectionId(Object cacheKey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
public Object getNaturalIdValues(Object cacheKey) {
|
||||||
return staticGetNaturalIdValues(cacheKey);
|
return staticGetNaturalIdValues(cacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,12 @@
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.ValueHolder;
|
import org.hibernate.internal.util.ValueHolder;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,7 +27,7 @@
|
|||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class NaturalIdCacheKey implements Serializable {
|
public class NaturalIdCacheKey implements Serializable {
|
||||||
private final Object[] naturalIdValues;
|
private final Object naturalIdValues;
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
private final String tenantId;
|
private final String tenantId;
|
||||||
private final int hashCode;
|
private final int hashCode;
|
||||||
@ -43,40 +42,20 @@ public class NaturalIdCacheKey implements Serializable {
|
|||||||
* @param session The originating session
|
* @param session The originating session
|
||||||
*/
|
*/
|
||||||
public NaturalIdCacheKey(
|
public NaturalIdCacheKey(
|
||||||
final Object[] naturalIdValues,
|
final Object naturalIdValues,
|
||||||
Type[] propertyTypes, int[] naturalIdPropertyIndexes, final String entityName,
|
Type[] propertyTypes,
|
||||||
|
int[] naturalIdPropertyIndexes,
|
||||||
|
final String entityName,
|
||||||
final SharedSessionContractImplementor session) {
|
final SharedSessionContractImplementor session) {
|
||||||
|
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.tenantId = session.getTenantIdentifier();
|
this.tenantId = session.getTenantIdentifier();
|
||||||
|
|
||||||
this.naturalIdValues = new Serializable[naturalIdValues.length];
|
final EntityMappingType entityMappingType = session.getFactory().getRuntimeMetamodels().getEntityMappingType( entityName );
|
||||||
|
final NaturalIdMapping naturalIdMapping = entityMappingType.getNaturalIdMapping();
|
||||||
|
|
||||||
final SessionFactoryImplementor factory = session.getFactory();
|
this.naturalIdValues = naturalIdMapping.disassemble( naturalIdValues, session );
|
||||||
|
this.hashCode = naturalIdMapping.calculateHashCode( naturalIdValues, session );
|
||||||
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ( ( this.entityName == null ) ? 0 : this.entityName.hashCode() );
|
|
||||||
result = prime * result + ( ( this.tenantId == null ) ? 0 : this.tenantId.hashCode() );
|
|
||||||
for ( int i = 0; i < naturalIdValues.length; i++ ) {
|
|
||||||
final int naturalIdPropertyIndex = naturalIdPropertyIndexes[i];
|
|
||||||
final Type type = propertyTypes[naturalIdPropertyIndex];
|
|
||||||
final Object value = naturalIdValues[i];
|
|
||||||
|
|
||||||
result = prime * result + (value != null ? type.getHashCode( value, factory ) : 0);
|
|
||||||
|
|
||||||
// The natural id may not be fully resolved in some situations. See HHH-7513 for one of them
|
|
||||||
// (re-attaching a mutable natural id uses a database snapshot and hydration does not resolve associations).
|
|
||||||
// TODO: The snapshot should probably be revisited at some point. Consider semi-resolving, hydrating, etc.
|
|
||||||
if (type instanceof EntityType && type.getSemiResolvedType( factory ).getReturnedClass().isInstance( value )) {
|
|
||||||
this.naturalIdValues[i] = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.naturalIdValues[i] = type.disassemble( value, session, null );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hashCode = result;
|
|
||||||
initTransients();
|
initTransients();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,15 +66,20 @@ private void initTransients() {
|
|||||||
public String initialize() {
|
public String initialize() {
|
||||||
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
|
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
|
||||||
//the only same way to differentiate the keys is to include the disassembled values in the string.
|
//the only same way to differentiate the keys is to include the disassembled values in the string.
|
||||||
final StringBuilder toStringBuilder = new StringBuilder().append( entityName ).append(
|
final StringBuilder toStringBuilder = new StringBuilder()
|
||||||
"##NaturalId[" );
|
.append( entityName ).append( "##NaturalId[" );
|
||||||
for ( int i = 0; i < naturalIdValues.length; i++ ) {
|
if ( naturalIdValues instanceof Object[] ) {
|
||||||
toStringBuilder.append( naturalIdValues[i] );
|
final Object[] values = (Object[]) naturalIdValues;
|
||||||
if ( i + 1 < naturalIdValues.length ) {
|
for ( int i = 0; i < values.length; i++ ) {
|
||||||
toStringBuilder.append( ", " );
|
toStringBuilder.append( values[ i ] );
|
||||||
|
if ( i + 1 < values.length ) {
|
||||||
|
toStringBuilder.append( ", " );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toStringBuilder.append( "]" );
|
else {
|
||||||
|
toStringBuilder.append( naturalIdValues );
|
||||||
|
}
|
||||||
|
|
||||||
return toStringBuilder.toString();
|
return toStringBuilder.toString();
|
||||||
}
|
}
|
||||||
@ -114,7 +98,7 @@ public String getTenantId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"UnusedDeclaration"})
|
@SuppressWarnings( {"UnusedDeclaration"})
|
||||||
public Object[] getNaturalIdValues() {
|
public Object getNaturalIdValues() {
|
||||||
return naturalIdValues;
|
return naturalIdValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +129,7 @@ public boolean equals(Object o) {
|
|||||||
final NaturalIdCacheKey other = (NaturalIdCacheKey) o;
|
final NaturalIdCacheKey other = (NaturalIdCacheKey) o;
|
||||||
return Objects.equals( entityName, other.entityName )
|
return Objects.equals( entityName, other.entityName )
|
||||||
&& Objects.equals( tenantId, other.tenantId )
|
&& Objects.equals( tenantId, other.tenantId )
|
||||||
&& Arrays.deepEquals( this.naturalIdValues, other.naturalIdValues );
|
&& Objects.deepEquals( this.naturalIdValues, other.naturalIdValues );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream ois)
|
private void readObject(ObjectInputStream ois)
|
||||||
|
@ -32,7 +32,7 @@ public Object createEntityKey(Object id, EntityPersister persister, SessionFacto
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
public Object createNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||||
// natural ids always need to be wrapped
|
// natural ids always need to be wrapped
|
||||||
return new NaturalIdCacheKey(naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), null, session);
|
return new NaturalIdCacheKey(naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), null, session);
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ public Object getCollectionId(Object cacheKey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
public Object getNaturalIdValues(Object cacheKey) {
|
||||||
return ((NaturalIdCacheKey) cacheKey).getNaturalIdValues();
|
return ((NaturalIdCacheKey) cacheKey).getNaturalIdValues();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@ public interface CacheKeysFactory {
|
|||||||
|
|
||||||
Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier);
|
Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier);
|
||||||
|
|
||||||
Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session);
|
Object createNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
Object getEntityId(Object cacheKey);
|
Object getEntityId(Object cacheKey);
|
||||||
|
|
||||||
Object getCollectionId(Object cacheKey);
|
Object getCollectionId(Object cacheKey);
|
||||||
|
|
||||||
Object[] getNaturalIdValues(Object cacheKey);
|
Object getNaturalIdValues(Object cacheKey);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public interface NaturalIdDataAccess extends CachedDomainDataAccess {
|
|||||||
* @return a key which can be used to identify an element unequivocally on this same region
|
* @return a key which can be used to identify an element unequivocally on this same region
|
||||||
*/
|
*/
|
||||||
Object generateCacheKey(
|
Object generateCacheKey(
|
||||||
Object[] naturalIdValues,
|
Object naturalIdValues,
|
||||||
EntityPersister rootEntityDescriptor,
|
EntityPersister rootEntityDescriptor,
|
||||||
SharedSessionContractImplementor session);
|
SharedSessionContractImplementor session);
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ Object generateCacheKey(
|
|||||||
*
|
*
|
||||||
* @return the sequence of values which unequivocally identifies a cached element on this region
|
* @return the sequence of values which unequivocally identifies a cached element on this region
|
||||||
*/
|
*/
|
||||||
Object[] getNaturalIdValues(Object cacheKey);
|
Object getNaturalIdValues(Object cacheKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called afterQuery an item has been inserted (beforeQuery the transaction completes),
|
* Called afterQuery an item has been inserted (beforeQuery the transaction completes),
|
||||||
|
@ -31,14 +31,14 @@ public AbstractNaturalIdDataAccess(
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object generateCacheKey(
|
public Object generateCacheKey(
|
||||||
Object[] naturalIdValues,
|
Object naturalIdValues,
|
||||||
EntityPersister persister,
|
EntityPersister persister,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
return keysFactory.createNaturalIdKey( naturalIdValues, persister, session );
|
return keysFactory.createNaturalIdKey( naturalIdValues, persister, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
public Object getNaturalIdValues(Object cacheKey) {
|
||||||
return keysFactory.getNaturalIdValues( cacheKey );
|
return keysFactory.getNaturalIdValues( cacheKey );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,14 +53,14 @@ protected Comparator getVersionComparator() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object generateCacheKey(
|
public Object generateCacheKey(
|
||||||
Object[] naturalIdValues,
|
Object naturalIdValues,
|
||||||
EntityPersister rootEntityDescriptor,
|
EntityPersister rootEntityDescriptor,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
return keysFactory.createNaturalIdKey( naturalIdValues, rootEntityDescriptor, session );
|
return keysFactory.createNaturalIdKey( naturalIdValues, rootEntityDescriptor, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNaturalIdValues(Object cacheKey) {
|
public Object getNaturalIdValues(Object cacheKey) {
|
||||||
return keysFactory.getNaturalIdValues( cacheKey );
|
return keysFactory.getNaturalIdValues( cacheKey );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,11 +408,8 @@ public void setReadOnly(boolean readOnly, Object entity) {
|
|||||||
}
|
}
|
||||||
setStatus( Status.MANAGED );
|
setStatus( Status.MANAGED );
|
||||||
loadedState = getPersister().getPropertyValues( entity );
|
loadedState = getPersister().getPropertyValues( entity );
|
||||||
getPersistenceContext().getNaturalIdHelper().manageLocalNaturalIdCrossReference(
|
getPersistenceContext().getNaturalIdHelper().manageLocalResolution(
|
||||||
persister,
|
id, loadedState, persister,
|
||||||
id,
|
|
||||||
loadedState,
|
|
||||||
null,
|
|
||||||
CachedNaturalIdValueSource.LOAD
|
CachedNaturalIdValueSource.LOAD
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -19,10 +18,10 @@
|
|||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.stat.internal.StatsHelper;
|
import org.hibernate.stat.internal.StatsHelper;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
import org.hibernate.type.Type;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
@ -70,12 +69,12 @@ protected SharedSessionContractImplementor session() {
|
|||||||
*
|
*
|
||||||
* @return {@code true} if a new entry was actually added; {@code false} otherwise.
|
* @return {@code true} if a new entry was actually added; {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean cacheNaturalIdCrossReference(EntityPersister persister, Object pk, Object[] naturalIdValues) {
|
public boolean cacheResolution(EntityPersister persister, Object pk, Object naturalIdValues) {
|
||||||
validateNaturalId( persister, naturalIdValues );
|
validateNaturalId( persister, naturalIdValues );
|
||||||
|
|
||||||
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||||
if ( entityNaturalIdResolutionCache == null ) {
|
if ( entityNaturalIdResolutionCache == null ) {
|
||||||
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister );
|
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister, persistenceContext );
|
||||||
NaturalIdResolutionCache previousInstance = naturalIdResolutionCacheMap.putIfAbsent( persister, entityNaturalIdResolutionCache );
|
NaturalIdResolutionCache previousInstance = naturalIdResolutionCacheMap.putIfAbsent( persister, entityNaturalIdResolutionCache );
|
||||||
if ( previousInstance != null ) {
|
if ( previousInstance != null ) {
|
||||||
entityNaturalIdResolutionCache = previousInstance;
|
entityNaturalIdResolutionCache = previousInstance;
|
||||||
@ -93,29 +92,29 @@ public boolean cacheNaturalIdCrossReference(EntityPersister persister, Object pk
|
|||||||
*
|
*
|
||||||
* @return The cached values, if any. May be different from incoming values.
|
* @return The cached values, if any. May be different from incoming values.
|
||||||
*/
|
*/
|
||||||
public Object[] removeNaturalIdCrossReference(EntityPersister persister, Object pk, Object[] naturalIdValues) {
|
public Object removeResolutions(EntityPersister persister, Object pk, Object naturalIdValues) {
|
||||||
persister = locatePersisterForKey( persister );
|
persister = locatePersisterForKey( persister );
|
||||||
|
|
||||||
|
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
validateNaturalId( persister, naturalIdValues );
|
validateNaturalId( persister, naturalIdValues );
|
||||||
|
|
||||||
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||||
Object[] sessionCachedNaturalIdValues = null;
|
Object sessionCachedNaturalIdValues = null;
|
||||||
if ( entityNaturalIdResolutionCache != null ) {
|
if ( entityNaturalIdResolutionCache != null ) {
|
||||||
final CachedNaturalId cachedNaturalId = entityNaturalIdResolutionCache.pkToNaturalIdMap
|
final CachedNaturalId cachedNaturalId = entityNaturalIdResolutionCache.pkToNaturalIdMap.remove( pk );
|
||||||
.remove( pk );
|
|
||||||
if ( cachedNaturalId != null ) {
|
if ( cachedNaturalId != null ) {
|
||||||
entityNaturalIdResolutionCache.naturalIdToPkMap.remove( cachedNaturalId );
|
entityNaturalIdResolutionCache.naturalIdToPkMap.remove( cachedNaturalId );
|
||||||
sessionCachedNaturalIdValues = cachedNaturalId.getValues();
|
sessionCachedNaturalIdValues = cachedNaturalId.getNaturalId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( persister.hasNaturalIdCache() ) {
|
if ( persister.hasNaturalIdCache() ) {
|
||||||
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister
|
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
|
||||||
.getNaturalIdCacheAccessStrategy();
|
|
||||||
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session() );
|
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session() );
|
||||||
naturalIdCacheAccessStrategy.evict( naturalIdCacheKey );
|
naturalIdCacheAccessStrategy.evict( naturalIdCacheKey );
|
||||||
|
|
||||||
if ( sessionCachedNaturalIdValues != null
|
if ( sessionCachedNaturalIdValues != null
|
||||||
&& !Arrays.equals( sessionCachedNaturalIdValues, naturalIdValues ) ) {
|
&& ! naturalIdMapping.areEqual( sessionCachedNaturalIdValues, naturalIdValues, session() ) ) {
|
||||||
final Object sessionNaturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( sessionCachedNaturalIdValues, persister, session() );
|
final Object sessionNaturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( sessionCachedNaturalIdValues, persister, session() );
|
||||||
naturalIdCacheAccessStrategy.evict( sessionNaturalIdCacheKey );
|
naturalIdCacheAccessStrategy.evict( sessionNaturalIdCacheKey );
|
||||||
}
|
}
|
||||||
@ -133,7 +132,7 @@ public Object[] removeNaturalIdCrossReference(EntityPersister persister, Object
|
|||||||
*
|
*
|
||||||
* @return {@code true} if the given naturalIdValues match the current cached values; {@code false} otherwise.
|
* @return {@code true} if the given naturalIdValues match the current cached values; {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean sameAsCached(EntityPersister persister, Object pk, Object[] naturalIdValues) {
|
public boolean sameAsCached(EntityPersister persister, Object pk, Object naturalIdValues) {
|
||||||
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||||
return entityNaturalIdResolutionCache != null
|
return entityNaturalIdResolutionCache != null
|
||||||
&& entityNaturalIdResolutionCache.sameAsCached( pk, naturalIdValues );
|
&& entityNaturalIdResolutionCache.sameAsCached( pk, naturalIdValues );
|
||||||
@ -157,16 +156,17 @@ protected EntityPersister locatePersisterForKey(EntityPersister persister) {
|
|||||||
* <li>the number of natural id values matches the expected number</li>
|
* <li>the number of natural id values matches the expected number</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param persister The persister representing the entity type.
|
* @param entityDescriptor The entity type descriptor
|
||||||
* @param naturalIdValues The natural id values
|
* @param naturalIdValues The natural id values
|
||||||
*/
|
*/
|
||||||
protected void validateNaturalId(EntityPersister persister, Object[] naturalIdValues) {
|
protected void validateNaturalId(EntityPersister entityDescriptor, Object naturalIdValues) {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
final NaturalIdMapping naturalIdMapping = entityDescriptor.getNaturalIdMapping();
|
||||||
|
|
||||||
|
if ( naturalIdMapping == null ) {
|
||||||
throw new IllegalArgumentException( "Entity did not define a natural-id" );
|
throw new IllegalArgumentException( "Entity did not define a natural-id" );
|
||||||
}
|
}
|
||||||
if ( persister.getNaturalIdentifierProperties().length != naturalIdValues.length ) {
|
|
||||||
throw new IllegalArgumentException( "Mismatch between expected number of natural-id values and found." );
|
naturalIdMapping.validateInternalForm( naturalIdValues, persistenceContext.getSession() );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,7 +177,7 @@ protected void validateNaturalId(EntityPersister persister, Object[] naturalIdVa
|
|||||||
*
|
*
|
||||||
* @return The corresponding cross-referenced natural id values, or {@code null} if none
|
* @return The corresponding cross-referenced natural id values, or {@code null} if none
|
||||||
*/
|
*/
|
||||||
public Object[] findCachedNaturalId(EntityPersister persister, Object pk) {
|
public Object findCachedNaturalId(EntityPersister persister, Object pk) {
|
||||||
persister = locatePersisterForKey( persister );
|
persister = locatePersisterForKey( persister );
|
||||||
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||||
if ( entityNaturalIdResolutionCache == null ) {
|
if ( entityNaturalIdResolutionCache == null ) {
|
||||||
@ -189,7 +189,7 @@ public Object[] findCachedNaturalId(EntityPersister persister, Object pk) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedNaturalId.getValues();
|
return cachedNaturalId.getNaturalId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -199,19 +199,19 @@ public Object[] findCachedNaturalId(EntityPersister persister, Object pk) {
|
|||||||
*
|
*
|
||||||
* @param persister The persister representing the entity type.
|
* @param persister The persister representing the entity type.
|
||||||
* @param naturalIdValues The natural id value(s)
|
* @param naturalIdValues The natural id value(s)
|
||||||
*
|
*
|
||||||
* @return The corresponding cross-referenced primary key,
|
* @return The corresponding cross-referenced primary key,
|
||||||
* {@link PersistenceContext.NaturalIdHelper#INVALID_NATURAL_ID_REFERENCE},
|
* {@link PersistenceContext.NaturalIdHelper#INVALID_NATURAL_ID_REFERENCE},
|
||||||
* or {@code null} if none
|
* or {@code null} if none
|
||||||
*/
|
*/
|
||||||
public Object findCachedNaturalIdResolution(EntityPersister persister, Object[] naturalIdValues) {
|
public Object findResolution(EntityPersister persister, Object naturalIdValues) {
|
||||||
persister = locatePersisterForKey( persister );
|
persister = locatePersisterForKey( persister );
|
||||||
validateNaturalId( persister, naturalIdValues );
|
validateNaturalId( persister, naturalIdValues );
|
||||||
|
|
||||||
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||||
|
|
||||||
Object pk;
|
Object pk;
|
||||||
final CachedNaturalId cachedNaturalId = new CachedNaturalId( persister, naturalIdValues );
|
final CachedNaturalId cachedNaturalId = new CachedNaturalId( naturalIdValues, persister, persistenceContext );
|
||||||
if ( entityNaturalIdResolutionCache != null ) {
|
if ( entityNaturalIdResolutionCache != null ) {
|
||||||
pk = entityNaturalIdResolutionCache.naturalIdToPkMap.get( cachedNaturalId );
|
pk = entityNaturalIdResolutionCache.naturalIdToPkMap.get( cachedNaturalId );
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ public Object findCachedNaturalIdResolution(EntityPersister persister, Object[]
|
|||||||
LOG.trace(
|
LOG.trace(
|
||||||
"Resolved natural key -> primary key resolution in session cache: " +
|
"Resolved natural key -> primary key resolution in session cache: " +
|
||||||
persister.getRootEntityName() + "#[" +
|
persister.getRootEntityName() + "#[" +
|
||||||
Arrays.toString( naturalIdValues ) + "]"
|
naturalIdValues + "]"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,14 +264,14 @@ public Object findCachedNaturalIdResolution(EntityPersister persister, Object[]
|
|||||||
// protected to avoid Arrays.toString call unless needed
|
// protected to avoid Arrays.toString call unless needed
|
||||||
LOG.tracef(
|
LOG.tracef(
|
||||||
"Found natural key [%s] -> primary key [%s] xref in second-level cache for %s",
|
"Found natural key [%s] -> primary key [%s] xref in second-level cache for %s",
|
||||||
Arrays.toString( naturalIdValues ),
|
naturalIdValues,
|
||||||
pk,
|
pk,
|
||||||
persister.getRootEntityName()
|
persister.getRootEntityName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( entityNaturalIdResolutionCache == null ) {
|
if ( entityNaturalIdResolutionCache == null ) {
|
||||||
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister );
|
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister, persistenceContext );
|
||||||
NaturalIdResolutionCache existingCache = naturalIdResolutionCacheMap.putIfAbsent( persister, entityNaturalIdResolutionCache );
|
NaturalIdResolutionCache existingCache = naturalIdResolutionCacheMap.putIfAbsent( persister, entityNaturalIdResolutionCache );
|
||||||
if ( existingCache != null ) {
|
if ( existingCache != null ) {
|
||||||
entityNaturalIdResolutionCache = existingCache;
|
entityNaturalIdResolutionCache = existingCache;
|
||||||
@ -329,7 +329,7 @@ public Collection<Object> getCachedPkResolutions(EntityPersister persister) {
|
|||||||
*
|
*
|
||||||
* @see org.hibernate.NaturalIdLoadAccess#setSynchronizationEnabled
|
* @see org.hibernate.NaturalIdLoadAccess#setSynchronizationEnabled
|
||||||
*/
|
*/
|
||||||
public void stashInvalidNaturalIdReference(EntityPersister persister, Object[] invalidNaturalIdValues) {
|
public void stashInvalidNaturalIdReference(EntityPersister persister, Object invalidNaturalIdValues) {
|
||||||
persister = locatePersisterForKey( persister );
|
persister = locatePersisterForKey( persister );
|
||||||
|
|
||||||
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
final NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
|
||||||
@ -354,35 +354,27 @@ public void unStashInvalidNaturalIdReferences() {
|
|||||||
* Used to put natural id values into collections. Useful mainly to apply equals/hashCode implementations.
|
* Used to put natural id values into collections. Useful mainly to apply equals/hashCode implementations.
|
||||||
*/
|
*/
|
||||||
private static class CachedNaturalId implements Serializable {
|
private static class CachedNaturalId implements Serializable {
|
||||||
|
private final PersistenceContext persistenceContext;
|
||||||
private final EntityPersister persister;
|
private final EntityPersister persister;
|
||||||
private final Object[] values;
|
private final Object naturalId;
|
||||||
private final Type[] naturalIdTypes;
|
|
||||||
private int hashCode;
|
private int hashCode;
|
||||||
|
|
||||||
public CachedNaturalId(EntityPersister persister, Object[] values) {
|
public CachedNaturalId(Object naturalIdValue, EntityPersister persister, PersistenceContext persistenceContext) {
|
||||||
|
this.persistenceContext = persistenceContext;
|
||||||
|
|
||||||
this.persister = persister;
|
this.persister = persister;
|
||||||
this.values = values;
|
this.naturalId = naturalIdValue;
|
||||||
|
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int hashCodeCalculation = 1;
|
int hashCodeCalculation = 1;
|
||||||
hashCodeCalculation = prime * hashCodeCalculation + persister.hashCode();
|
hashCodeCalculation = prime * hashCodeCalculation + persister.hashCode();
|
||||||
|
hashCodeCalculation = prime * hashCodeCalculation + persister.getNaturalIdMapping().calculateHashCode( naturalIdValue, persistenceContext.getSession());
|
||||||
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;
|
|
||||||
final int elementHashCode = values[i] == null ? 0 :type.getHashCode( values[i], persister.getFactory() );
|
|
||||||
hashCodeCalculation = prime * hashCodeCalculation + elementHashCode;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hashCode = hashCodeCalculation;
|
this.hashCode = hashCodeCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] getValues() {
|
public Object getNaturalId() {
|
||||||
return values;
|
return naturalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -403,17 +395,11 @@ public boolean equals(Object obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final CachedNaturalId other = (CachedNaturalId) obj;
|
final CachedNaturalId other = (CachedNaturalId) obj;
|
||||||
return persister.equals( other.persister ) && isSame( other.values );
|
return persister.equals( other.persister ) && isSame( other.naturalId );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSame(Object[] otherValues) {
|
private boolean isSame(Object otherValue) {
|
||||||
// lengths have already been verified at this point
|
return persister.getNaturalIdMapping().areEqual( naturalId, otherValue, persistenceContext.getSession() );
|
||||||
for ( int i = 0; i < naturalIdTypes.length; i++ ) {
|
|
||||||
if ( ! naturalIdTypes[i].isEqual( values[i], otherValues[i], persister.getFactory() ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,6 +407,8 @@ private boolean isSame(Object[] otherValues) {
|
|||||||
* Represents the persister-specific cross-reference cache.
|
* Represents the persister-specific cross-reference cache.
|
||||||
*/
|
*/
|
||||||
private static class NaturalIdResolutionCache implements Serializable {
|
private static class NaturalIdResolutionCache implements Serializable {
|
||||||
|
private final PersistenceContext persistenceContext;
|
||||||
|
|
||||||
private final EntityPersister persister;
|
private final EntityPersister persister;
|
||||||
|
|
||||||
private Map<Object, CachedNaturalId> pkToNaturalIdMap = new ConcurrentHashMap<>();
|
private Map<Object, CachedNaturalId> pkToNaturalIdMap = new ConcurrentHashMap<>();
|
||||||
@ -428,15 +416,16 @@ private static class NaturalIdResolutionCache implements Serializable {
|
|||||||
|
|
||||||
private List<CachedNaturalId> invalidNaturalIdList;
|
private List<CachedNaturalId> invalidNaturalIdList;
|
||||||
|
|
||||||
private NaturalIdResolutionCache(EntityPersister persister) {
|
private NaturalIdResolutionCache(EntityPersister persister, PersistenceContext persistenceContext) {
|
||||||
this.persister = persister;
|
this.persister = persister;
|
||||||
|
this.persistenceContext = persistenceContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityPersister getPersister() {
|
public EntityPersister getPersister() {
|
||||||
return persister;
|
return persister;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean sameAsCached(Object pk, Object[] naturalIdValues) {
|
public boolean sameAsCached(Object pk, Object naturalIdValues) {
|
||||||
if ( pk == null ) {
|
if ( pk == null ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -449,7 +438,7 @@ public boolean sameAsCached(Object pk, Object[] naturalIdValues) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean cache(Object pk, Object[] naturalIdValues) {
|
public boolean cache(Object pk, Object naturalIdValues) {
|
||||||
if ( pk == null ) {
|
if ( pk == null ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -461,23 +450,23 @@ public boolean cache(Object pk, Object[] naturalIdValues) {
|
|||||||
naturalIdToPkMap.remove( initial );
|
naturalIdToPkMap.remove( initial );
|
||||||
}
|
}
|
||||||
|
|
||||||
final CachedNaturalId cachedNaturalId = new CachedNaturalId( persister, naturalIdValues );
|
final CachedNaturalId cachedNaturalId = new CachedNaturalId( naturalIdValues, persister, persistenceContext );
|
||||||
pkToNaturalIdMap.put( pk, cachedNaturalId );
|
pkToNaturalIdMap.put( pk, cachedNaturalId );
|
||||||
naturalIdToPkMap.put( cachedNaturalId, pk );
|
naturalIdToPkMap.put( cachedNaturalId, pk );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stashInvalidNaturalIdReference(Object[] invalidNaturalIdValues) {
|
public void stashInvalidNaturalIdReference(Object invalidNaturalIdValues) {
|
||||||
if ( invalidNaturalIdList == null ) {
|
if ( invalidNaturalIdList == null ) {
|
||||||
invalidNaturalIdList = new ArrayList<>();
|
invalidNaturalIdList = new ArrayList<>();
|
||||||
}
|
}
|
||||||
invalidNaturalIdList.add( new CachedNaturalId( persister, invalidNaturalIdValues ) );
|
invalidNaturalIdList.add( new CachedNaturalId( invalidNaturalIdValues, persister, persistenceContext ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsInvalidNaturalIdReference(Object[] naturalIdValues) {
|
public boolean containsInvalidNaturalIdReference(Object naturalIdValues) {
|
||||||
return invalidNaturalIdList != null
|
return invalidNaturalIdList != null
|
||||||
&& invalidNaturalIdList.contains( new CachedNaturalId( persister, naturalIdValues ) );
|
&& invalidNaturalIdList.contains( new CachedNaturalId( naturalIdValues, persister, persistenceContext ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unStashInvalidNaturalIdReferences() {
|
public void unStashInvalidNaturalIdReferences() {
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.internal.util.collections.ConcurrentReferenceHashMap;
|
import org.hibernate.internal.util.collections.ConcurrentReferenceHashMap;
|
||||||
import org.hibernate.internal.util.collections.IdentityMap;
|
import org.hibernate.internal.util.collections.IdentityMap;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
@ -328,7 +329,7 @@ public Object[] getDatabaseSnapshot(Object id, EntityPersister persister) throws
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getNaturalIdSnapshot(Object id, EntityPersister persister) throws HibernateException {
|
public Object getNaturalIdSnapshot(Object id, EntityPersister persister) throws HibernateException {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
if ( !persister.hasNaturalIdentifier() ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -336,7 +337,7 @@ public Object[] getNaturalIdSnapshot(Object id, EntityPersister persister) throw
|
|||||||
persister = locateProperPersister( persister );
|
persister = locateProperPersister( persister );
|
||||||
|
|
||||||
// let's first see if it is part of the natural id cache...
|
// let's first see if it is part of the natural id cache...
|
||||||
final Object[] cachedValue = naturalIdHelper.findCachedNaturalId( persister, id );
|
final Object cachedValue = naturalIdHelper.findCachedNaturalId( persister, id );
|
||||||
if ( cachedValue != null ) {
|
if ( cachedValue != null ) {
|
||||||
return cachedValue;
|
return cachedValue;
|
||||||
}
|
}
|
||||||
@ -345,7 +346,7 @@ public Object[] getNaturalIdSnapshot(Object id, EntityPersister persister) throw
|
|||||||
if ( persister.getEntityMetamodel().hasImmutableNaturalId() ) {
|
if ( persister.getEntityMetamodel().hasImmutableNaturalId() ) {
|
||||||
// an immutable natural-id is not retrieved during a normal database-snapshot operation...
|
// an immutable natural-id is not retrieved during a normal database-snapshot operation...
|
||||||
final Object[] dbValue = persister.getNaturalIdentifierSnapshot( id, session );
|
final Object[] dbValue = persister.getNaturalIdentifierSnapshot( id, session );
|
||||||
naturalIdHelper.cacheNaturalIdCrossReferenceFromLoad(
|
naturalIdHelper.cacheResolutionFromLoad(
|
||||||
persister,
|
persister,
|
||||||
id,
|
id,
|
||||||
dbValue
|
dbValue
|
||||||
@ -365,7 +366,7 @@ public Object[] getNaturalIdSnapshot(Object id, EntityPersister persister) throw
|
|||||||
for ( int i = 0; i < props.length; i++ ) {
|
for ( int i = 0; i < props.length; i++ ) {
|
||||||
naturalIdSnapshotSubSet[i] = entitySnapshot[ props[i] ];
|
naturalIdSnapshotSubSet[i] = entitySnapshot[ props[i] ];
|
||||||
}
|
}
|
||||||
naturalIdHelper.cacheNaturalIdCrossReferenceFromLoad(
|
naturalIdHelper.cacheResolutionFromLoad(
|
||||||
persister,
|
persister,
|
||||||
id,
|
id,
|
||||||
naturalIdSnapshotSubSet
|
naturalIdSnapshotSubSet
|
||||||
@ -1947,10 +1948,10 @@ private NaturalIdXrefDelegate getNaturalIdXrefDelegate() {
|
|||||||
|
|
||||||
private final NaturalIdHelper naturalIdHelper = new NaturalIdHelper() {
|
private final NaturalIdHelper naturalIdHelper = new NaturalIdHelper() {
|
||||||
@Override
|
@Override
|
||||||
public void cacheNaturalIdCrossReferenceFromLoad(
|
public void cacheResolutionFromLoad(
|
||||||
EntityPersister persister,
|
EntityPersister persister,
|
||||||
Object id,
|
Object id,
|
||||||
Object[] naturalIdValues) {
|
Object naturalIdValues) {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
if ( !persister.hasNaturalIdentifier() ) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
@ -1962,19 +1963,18 @@ public void cacheNaturalIdCrossReferenceFromLoad(
|
|||||||
// from a single load event. The first put journal would come from the natural id resolution;
|
// from a single load event. The first put journal would come from the natural id resolution;
|
||||||
// the second comes from the entity loading. In this condition, we want to avoid the multiple
|
// the second comes from the entity loading. In this condition, we want to avoid the multiple
|
||||||
// 'put' stats incrementing.
|
// 'put' stats incrementing.
|
||||||
final boolean justAddedLocally = getNaturalIdXrefDelegate().cacheNaturalIdCrossReference( persister, id, naturalIdValues );
|
final boolean justAddedLocally = getNaturalIdXrefDelegate().cacheResolution( persister, id, naturalIdValues );
|
||||||
|
|
||||||
if ( justAddedLocally && persister.hasNaturalIdCache() ) {
|
if ( justAddedLocally && persister.hasNaturalIdCache() ) {
|
||||||
managedSharedCacheEntries( persister, id, naturalIdValues, null, CachedNaturalIdValueSource.LOAD );
|
managedSharedResolutions( persister, id, naturalIdValues, null, CachedNaturalIdValueSource.LOAD );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void manageLocalNaturalIdCrossReference(
|
public void manageLocalResolution(
|
||||||
EntityPersister persister,
|
|
||||||
Object id,
|
Object id,
|
||||||
Object[] state,
|
Object naturalId,
|
||||||
Object[] previousState,
|
EntityPersister persister,
|
||||||
CachedNaturalIdValueSource source) {
|
CachedNaturalIdValueSource source) {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
if ( !persister.hasNaturalIdentifier() ) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
@ -1982,18 +1982,17 @@ public void manageLocalNaturalIdCrossReference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
persister = locateProperPersister( persister );
|
persister = locateProperPersister( persister );
|
||||||
final Object[] naturalIdValues = extractNaturalIdValues( state, persister );
|
|
||||||
|
|
||||||
// cache
|
// cache
|
||||||
getNaturalIdXrefDelegate().cacheNaturalIdCrossReference( persister, id, naturalIdValues );
|
getNaturalIdXrefDelegate().cacheResolution( persister, id, naturalId );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void manageSharedNaturalIdCrossReference(
|
public void manageSharedResolution(
|
||||||
EntityPersister persister,
|
|
||||||
final Object id,
|
final Object id,
|
||||||
Object[] state,
|
Object naturalId,
|
||||||
Object[] previousState,
|
Object previousNaturalId,
|
||||||
|
EntityPersister persister,
|
||||||
CachedNaturalIdValueSource source) {
|
CachedNaturalIdValueSource source) {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
if ( !persister.hasNaturalIdentifier() ) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
@ -2006,17 +2005,17 @@ public void manageSharedNaturalIdCrossReference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
persister = locateProperPersister( persister );
|
persister = locateProperPersister( persister );
|
||||||
final Object[] naturalIdValues = extractNaturalIdValues( state, persister );
|
final Object naturalIdValues = extractNaturalIdValues( naturalId, persister );
|
||||||
final Object[] previousNaturalIdValues = previousState == null ? null : extractNaturalIdValues( previousState, persister );
|
final Object previousNaturalIdValues = previousNaturalId == null ? null : extractNaturalIdValues( previousNaturalId, persister );
|
||||||
|
|
||||||
managedSharedCacheEntries( persister, id, naturalIdValues, previousNaturalIdValues, source );
|
managedSharedResolutions( persister, id, naturalIdValues, previousNaturalIdValues, source );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void managedSharedCacheEntries(
|
private void managedSharedResolutions(
|
||||||
EntityPersister persister,
|
EntityPersister persister,
|
||||||
final Object id,
|
final Object id,
|
||||||
Object[] naturalIdValues,
|
Object naturalIdValues,
|
||||||
Object[] previousNaturalIdValues,
|
Object previousNaturalIdValues,
|
||||||
CachedNaturalIdValueSource source) {
|
CachedNaturalIdValueSource source) {
|
||||||
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
|
final NaturalIdDataAccess naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy();
|
||||||
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session );
|
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalIdValues, persister, session );
|
||||||
@ -2133,26 +2132,25 @@ public void doAfterTransactionCompletion(boolean success, SharedSessionContractI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] removeLocalNaturalIdCrossReference(EntityPersister persister, Object id, Object[] state) {
|
public Object removeLocalResolution(EntityPersister persister, Object id, Object naturalId) {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
if ( !persister.hasNaturalIdentifier() ) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
persister = locateProperPersister( persister );
|
persister = locateProperPersister( persister );
|
||||||
final Object[] naturalIdValues = getNaturalIdValues( state, persister );
|
|
||||||
|
|
||||||
final Object[] localNaturalIdValues = getNaturalIdXrefDelegate().removeNaturalIdCrossReference(
|
final Object localNaturalIdValues = getNaturalIdXrefDelegate().removeResolutions(
|
||||||
persister,
|
persister,
|
||||||
id,
|
id,
|
||||||
naturalIdValues
|
naturalId
|
||||||
);
|
);
|
||||||
|
|
||||||
return localNaturalIdValues != null ? localNaturalIdValues : naturalIdValues;
|
return localNaturalIdValues != null ? localNaturalIdValues : naturalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeSharedNaturalIdCrossReference(EntityPersister persister, Object id, Object[] naturalIdValues) {
|
public void removeSharedResolution(EntityPersister persister, Object id, Object naturalIdValues) {
|
||||||
if ( !persister.hasNaturalIdentifier() ) {
|
if ( !persister.hasNaturalIdentifier() ) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
@ -2180,46 +2178,37 @@ public void removeSharedNaturalIdCrossReference(EntityPersister persister, Objec
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] findCachedNaturalId(EntityPersister persister, Object pk) {
|
public Object findCachedNaturalId(EntityPersister persister, Object pk) {
|
||||||
return getNaturalIdXrefDelegate().findCachedNaturalId( locateProperPersister( persister ), pk );
|
return getNaturalIdXrefDelegate().findCachedNaturalId( locateProperPersister( persister ), pk );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object findCachedNaturalIdResolution(EntityPersister persister, Object[] naturalIdValues) {
|
public Object findCachedNaturalIdResolution(EntityPersister persister, Object[] naturalIdValues) {
|
||||||
return getNaturalIdXrefDelegate().findCachedNaturalIdResolution( locateProperPersister( persister ), naturalIdValues );
|
return getNaturalIdXrefDelegate().findResolution( locateProperPersister( persister ), naturalIdValues );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] extractNaturalIdValues(Object[] state, EntityPersister persister) {
|
public Object extractNaturalIdValues(Object[] state, EntityPersister persister) {
|
||||||
final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties();
|
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
if ( state.length == naturalIdPropertyIndexes.length ) {
|
assert naturalIdMapping != null;
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Object[] naturalIdValues = new Object[naturalIdPropertyIndexes.length];
|
return naturalIdMapping.extractNaturalIdValues( state, getSession() );
|
||||||
for ( int i = 0; i < naturalIdPropertyIndexes.length; i++ ) {
|
|
||||||
naturalIdValues[i] = state[naturalIdPropertyIndexes[i]];
|
|
||||||
}
|
|
||||||
return naturalIdValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] extractNaturalIdValues(Object entity, EntityPersister persister) {
|
public Object extractNaturalIdValues(Object entity, EntityPersister persister) {
|
||||||
if ( entity == null ) {
|
if ( entity == null ) {
|
||||||
throw new AssertionFailure( "Entity from which to extract natural id value(s) cannot be null" );
|
throw new AssertionFailure( "Entity from which to extract natural id value(s) cannot be null" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( persister == null ) {
|
if ( persister == null ) {
|
||||||
throw new AssertionFailure( "Persister to use in extracting natural id value(s) cannot be null" );
|
throw new AssertionFailure( "Persister to use in extracting natural id value(s) cannot be null" );
|
||||||
}
|
}
|
||||||
|
|
||||||
final int[] naturalIdentifierProperties = persister.getNaturalIdentifierProperties();
|
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
final Object[] naturalIdValues = new Object[naturalIdentifierProperties.length];
|
assert naturalIdMapping != null;
|
||||||
|
|
||||||
for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) {
|
return naturalIdMapping.extractNaturalIdValues( entity, session );
|
||||||
naturalIdValues[i] = persister.getPropertyValue( entity, naturalIdentifierProperties[i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
return naturalIdValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2236,7 +2225,7 @@ public void handleSynchronization(EntityPersister persister, Object pk, Object e
|
|||||||
|
|
||||||
persister = locateProperPersister( persister );
|
persister = locateProperPersister( persister );
|
||||||
|
|
||||||
final Object[] naturalIdValuesFromCurrentObjectState = extractNaturalIdValues( entity, persister );
|
final Object naturalIdValuesFromCurrentObjectState = extractNaturalIdValues( entity, persister );
|
||||||
final NaturalIdXrefDelegate naturalIdXrefDelegate = getNaturalIdXrefDelegate();
|
final NaturalIdXrefDelegate naturalIdXrefDelegate = getNaturalIdXrefDelegate();
|
||||||
final boolean changed = ! naturalIdXrefDelegate.sameAsCached(
|
final boolean changed = ! naturalIdXrefDelegate.sameAsCached(
|
||||||
persister,
|
persister,
|
||||||
@ -2245,11 +2234,11 @@ public void handleSynchronization(EntityPersister persister, Object pk, Object e
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ( changed ) {
|
if ( changed ) {
|
||||||
final Object[] cachedNaturalIdValues = naturalIdXrefDelegate.findCachedNaturalId( persister, pk );
|
final Object cachedNaturalIdValues = naturalIdXrefDelegate.findCachedNaturalId( persister, pk );
|
||||||
naturalIdXrefDelegate.cacheNaturalIdCrossReference( persister, pk, naturalIdValuesFromCurrentObjectState );
|
naturalIdXrefDelegate.cacheResolution( persister, pk, naturalIdValuesFromCurrentObjectState );
|
||||||
naturalIdXrefDelegate.stashInvalidNaturalIdReference( persister, cachedNaturalIdValues );
|
naturalIdXrefDelegate.stashInvalidNaturalIdReference( persister, cachedNaturalIdValues );
|
||||||
|
|
||||||
removeSharedNaturalIdCrossReference(
|
removeSharedResolution(
|
||||||
persister,
|
persister,
|
||||||
pk,
|
pk,
|
||||||
cachedNaturalIdValues
|
cachedNaturalIdValues
|
||||||
@ -2264,7 +2253,7 @@ public void cleanupFromSynchronizations() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleEviction(Object object, EntityPersister persister, Serializable identifier) {
|
public void handleEviction(Object object, EntityPersister persister, Serializable identifier) {
|
||||||
getNaturalIdXrefDelegate().removeNaturalIdCrossReference(
|
getNaturalIdXrefDelegate().removeResolutions(
|
||||||
persister,
|
persister,
|
||||||
identifier,
|
identifier,
|
||||||
findCachedNaturalId( persister, identifier )
|
findCachedNaturalId( persister, identifier )
|
||||||
@ -2276,15 +2265,4 @@ public void handleEviction(Object object, EntityPersister persister, Serializabl
|
|||||||
public NaturalIdHelper getNaturalIdHelper() {
|
public NaturalIdHelper getNaturalIdHelper() {
|
||||||
return naturalIdHelper;
|
return naturalIdHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object[] getNaturalIdValues(Object[] state, EntityPersister persister) {
|
|
||||||
final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties();
|
|
||||||
final Object[] naturalIdValues = new Object[naturalIdPropertyIndexes.length];
|
|
||||||
|
|
||||||
for ( int i = 0; i < naturalIdPropertyIndexes.length; i++ ) {
|
|
||||||
naturalIdValues[i] = state[naturalIdPropertyIndexes[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return naturalIdValues;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ public static void initializeEntityFromEntityEntryLoadedState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( persister.hasNaturalIdentifier() ) {
|
if ( persister.hasNaturalIdentifier() ) {
|
||||||
persistenceContext.getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad(
|
persistenceContext.getNaturalIdHelper().cacheResolutionFromLoad(
|
||||||
persister,
|
persister,
|
||||||
id,
|
id,
|
||||||
persistenceContext.getNaturalIdHelper().extractNaturalIdValues( hydratedState, persister )
|
persistenceContext.getNaturalIdHelper().extractNaturalIdValues( hydratedState, persister )
|
||||||
|
@ -147,7 +147,7 @@ public interface PersistenceContext {
|
|||||||
*
|
*
|
||||||
* @return The current (non-cached) snapshot of the entity's natural id state.
|
* @return The current (non-cached) snapshot of the entity's natural id state.
|
||||||
*/
|
*/
|
||||||
Object[] getNaturalIdSnapshot(Object id, EntityPersister persister);
|
Object getNaturalIdSnapshot(Object id, EntityPersister persister);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a canonical mapping from entity key to entity instance
|
* Add a canonical mapping from entity key to entity instance
|
||||||
@ -814,7 +814,7 @@ interface NaturalIdHelper {
|
|||||||
*
|
*
|
||||||
* @return The extracted natural id values
|
* @return The extracted natural id values
|
||||||
*/
|
*/
|
||||||
Object[] extractNaturalIdValues(Object[] state, EntityPersister persister);
|
Object extractNaturalIdValues(Object[] state, EntityPersister persister);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an entity instance, extract the values that represent the natural id
|
* Given an entity instance, extract the values that represent the natural id
|
||||||
@ -824,35 +824,27 @@ interface NaturalIdHelper {
|
|||||||
*
|
*
|
||||||
* @return The extracted natural id values
|
* @return The extracted natural id values
|
||||||
*/
|
*/
|
||||||
Object[] extractNaturalIdValues(Object entity, EntityPersister persister);
|
Object extractNaturalIdValues(Object entity, EntityPersister persister);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs processing related to creating natural-id cross-reference entries on load.
|
* Performs processing related to creating natural-id cross-reference entries on load.
|
||||||
* Handles both the local (transactional) and shared (second-level) caches.
|
* Handles both the local (transactional) and shared (second-level) caches.
|
||||||
* @param persister The persister representing the entity type.
|
* @param persister The persister representing the entity type.
|
||||||
* @param id The primary key value
|
* @param id The primary key value
|
||||||
* @param naturalIdValues The natural id values
|
* @param naturalIdValues The natural id values
|
||||||
*/
|
*/
|
||||||
void cacheNaturalIdCrossReferenceFromLoad(
|
void cacheResolutionFromLoad(
|
||||||
EntityPersister persister,
|
EntityPersister persister,
|
||||||
Object id,
|
Object id,
|
||||||
Object[] naturalIdValues);
|
Object naturalIdValues);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates necessary local cross-reference entries.
|
* Creates necessary local cross-reference entries.
|
||||||
*
|
|
||||||
* @param persister The persister representing the entity type.
|
|
||||||
* @param id The primary key value
|
|
||||||
* @param state Generally the "full entity state array", though could also be the natural id values array
|
|
||||||
* @param previousState Generally the "full entity state array", though could also be the natural id values array.
|
|
||||||
* Specifically represents the previous values on update, and so is only used with {@link CachedNaturalIdValueSource#UPDATE}
|
|
||||||
* @param source Enumeration representing how these values are coming into cache.
|
|
||||||
*/
|
*/
|
||||||
void manageLocalNaturalIdCrossReference(
|
void manageLocalResolution(
|
||||||
EntityPersister persister,
|
|
||||||
Object id,
|
Object id,
|
||||||
Object[] state,
|
Object naturalId,
|
||||||
Object[] previousState,
|
EntityPersister persister,
|
||||||
CachedNaturalIdValueSource source);
|
CachedNaturalIdValueSource source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -860,37 +852,29 @@ void manageLocalNaturalIdCrossReference(
|
|||||||
*
|
*
|
||||||
* @param persister The persister representing the entity type.
|
* @param persister The persister representing the entity type.
|
||||||
* @param id The primary key value
|
* @param id The primary key value
|
||||||
* @param state Generally the "full entity state array", though could also be the natural id values array
|
* @param naturalId Generally the "full entity state array", though could also be the natural id values array
|
||||||
*
|
*
|
||||||
* @return The local cached natural id values (could be different from given values).
|
* @return The local cached natural id values (could be different from given values).
|
||||||
*/
|
*/
|
||||||
Object[] removeLocalNaturalIdCrossReference(EntityPersister persister, Object id, Object[] state);
|
Object removeLocalResolution(EntityPersister persister, Object id, Object naturalId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates necessary shared (second level cache) cross-reference entries.
|
* Creates necessary shared (second level cache) cross-reference entries.
|
||||||
*
|
|
||||||
* @param persister The persister representing the entity type.
|
|
||||||
* @param id The primary key value
|
|
||||||
* @param state Generally the "full entity state array", though could also be the natural id values array
|
|
||||||
* @param previousState Generally the "full entity state array", though could also be the natural id values array.
|
|
||||||
* Specifically represents the previous values on update, and so is only used with {@link CachedNaturalIdValueSource#UPDATE}
|
|
||||||
* @param source Enumeration representing how these values are coming into cache.
|
|
||||||
*/
|
*/
|
||||||
void manageSharedNaturalIdCrossReference(
|
void manageSharedResolution(
|
||||||
EntityPersister persister,
|
|
||||||
Object id,
|
Object id,
|
||||||
Object[] state,
|
Object naturalId,
|
||||||
Object[] previousState,
|
Object previousNaturalId,
|
||||||
|
EntityPersister persister,
|
||||||
CachedNaturalIdValueSource source);
|
CachedNaturalIdValueSource source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up local cross-reference entries.
|
* Cleans up local cross-reference entries.
|
||||||
*
|
* @param persister The persister representing the entity type.
|
||||||
* @param persister The persister representing the entity type.
|
|
||||||
* @param id The primary key value
|
* @param id The primary key value
|
||||||
* @param naturalIdValues The natural id values array
|
* @param naturalIdValues The natural id values array
|
||||||
*/
|
*/
|
||||||
void removeSharedNaturalIdCrossReference(EntityPersister persister, Object id, Object[] naturalIdValues);
|
void removeSharedResolution(EntityPersister persister, Object id, Object naturalIdValues);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a persister and primary key, find the corresponding cross-referenced natural id values.
|
* Given a persister and primary key, find the corresponding cross-referenced natural id values.
|
||||||
@ -900,7 +884,7 @@ void manageSharedNaturalIdCrossReference(
|
|||||||
*
|
*
|
||||||
* @return The cross-referenced natural-id values, or {@code null}
|
* @return The cross-referenced natural-id values, or {@code null}
|
||||||
*/
|
*/
|
||||||
Object[] findCachedNaturalId(EntityPersister persister, Object pk);
|
Object findCachedNaturalId(EntityPersister persister, Object pk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a persister and natural-id values, find the corresponding cross-referenced primary key. Will return
|
* Given a persister and natural-id values, find the corresponding cross-referenced primary key. Will return
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
import org.hibernate.engine.internal.Versioning;
|
import org.hibernate.engine.internal.Versioning;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.ManagedEntity;
|
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
@ -38,9 +37,9 @@
|
|||||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||||
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
|
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
|
||||||
import org.hibernate.metadata.ClassMetadata;
|
import org.hibernate.metadata.ClassMetadata;
|
||||||
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
@ -103,48 +102,17 @@ private void checkNaturalId(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( persister.hasNaturalIdentifier() && entry.getStatus() != Status.READ_ONLY ) {
|
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
if ( !persister.getEntityMetamodel().hasImmutableNaturalId() ) {
|
if ( naturalIdMapping == null ) {
|
||||||
// EARLY EXIT!!!
|
return;
|
||||||
// the natural id is mutable (!immutable), no need to do the below checks
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int[] naturalIdentifierPropertiesIndexes = persister.getNaturalIdentifierProperties();
|
|
||||||
final Type[] propertyTypes = persister.getPropertyTypes();
|
|
||||||
final boolean[] propertyUpdateability = persister.getPropertyUpdateability();
|
|
||||||
|
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
|
||||||
final Object[] snapshot = loaded == null
|
|
||||||
? persistenceContext.getNaturalIdSnapshot( entry.getId(), persister )
|
|
||||||
: persistenceContext.getNaturalIdHelper().extractNaturalIdValues( loaded, persister );
|
|
||||||
|
|
||||||
for ( int i = 0; i < naturalIdentifierPropertiesIndexes.length; i++ ) {
|
|
||||||
final int naturalIdentifierPropertyIndex = naturalIdentifierPropertiesIndexes[i];
|
|
||||||
if ( propertyUpdateability[naturalIdentifierPropertyIndex] ) {
|
|
||||||
// if the given natural id property is updatable (mutable), there is nothing to check
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Type propertyType = propertyTypes[naturalIdentifierPropertyIndex];
|
|
||||||
if ( !propertyType.isEqual( current[naturalIdentifierPropertyIndex], snapshot[i] ) ) {
|
|
||||||
throw new HibernateException(
|
|
||||||
String.format(
|
|
||||||
"An immutable natural identifier of entity %s was altered from `%s` to `%s`",
|
|
||||||
persister.getEntityName(),
|
|
||||||
propertyTypes[naturalIdentifierPropertyIndex].toLoggableString(
|
|
||||||
snapshot[i],
|
|
||||||
session.getFactory()
|
|
||||||
),
|
|
||||||
propertyTypes[naturalIdentifierPropertyIndex].toLoggableString(
|
|
||||||
current[naturalIdentifierPropertyIndex],
|
|
||||||
session.getFactory()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( entry.getStatus() == Status.READ_ONLY ) {
|
||||||
|
// nothing to check
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
naturalIdMapping.verifyFlushState( entry.getId(), current, loaded, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -538,7 +538,7 @@ private Object doLoad(
|
|||||||
if ( entity != null && persister.hasNaturalIdentifier() ) {
|
if ( entity != null && persister.hasNaturalIdentifier() ) {
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
final PersistenceContext.NaturalIdHelper naturalIdHelper = persistenceContext.getNaturalIdHelper();
|
final PersistenceContext.NaturalIdHelper naturalIdHelper = persistenceContext.getNaturalIdHelper();
|
||||||
naturalIdHelper.cacheNaturalIdCrossReferenceFromLoad(
|
naturalIdHelper.cacheResolutionFromLoad(
|
||||||
persister,
|
persister,
|
||||||
event.getEntityId(),
|
event.getEntityId(),
|
||||||
naturalIdHelper.extractNaturalIdValues(
|
naturalIdHelper.extractNaturalIdValues(
|
||||||
|
@ -136,7 +136,7 @@ protected Object loadFromDatasource(final ResolveNaturalIdEvent event) {
|
|||||||
//PK can be null if the entity doesn't exist
|
//PK can be null if the entity doesn't exist
|
||||||
if (pk != null) {
|
if (pk != null) {
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
persistenceContext.getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad(
|
persistenceContext.getNaturalIdHelper().cacheResolutionFromLoad(
|
||||||
event.getEntityPersister(),
|
event.getEntityPersister(),
|
||||||
pk,
|
pk,
|
||||||
event.getOrderedNaturalIdValues()
|
event.getOrderedNaturalIdValues()
|
||||||
|
@ -75,7 +75,7 @@ public <K> List<E> multiLoad(K[] naturalIds, MultiNaturalIdLoadOptions options,
|
|||||||
(naturalId, session1) -> {
|
(naturalId, session1) -> {
|
||||||
// `naturalId` here is the one passed in by the API as part of the values array
|
// `naturalId` here is the one passed in by the API as part of the values array
|
||||||
// todo (6.0) : use this to help create the ordered results
|
// todo (6.0) : use this to help create the ordered results
|
||||||
return entityDescriptor.getNaturalIdMapping().normalizeValue( naturalId, session );
|
return entityDescriptor.getNaturalIdMapping().normalizeIncomingValue( naturalId, session );
|
||||||
},
|
},
|
||||||
session.getLoadQueryInfluencers(),
|
session.getLoadQueryInfluencers(),
|
||||||
lockOptions,
|
lockOptions,
|
||||||
|
@ -47,7 +47,7 @@ interface KeyValueResolver {
|
|||||||
* the "true" form - single value for simple natural-ids and an array for
|
* the "true" form - single value for simple natural-ids and an array for
|
||||||
* compound natural-ids.
|
* compound natural-ids.
|
||||||
*
|
*
|
||||||
* Generally delegates to {@link org.hibernate.metamodel.mapping.NaturalIdMapping#normalizeValue}
|
* Generally delegates to {@link org.hibernate.metamodel.mapping.NaturalIdMapping#normalizeIncomingValue}
|
||||||
*/
|
*/
|
||||||
Object resolveKeyToLoad(Object incoming, SharedSessionContractImplementor session);
|
Object resolveKeyToLoad(Object incoming, SharedSessionContractImplementor session);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ protected void applyNaturalIdAsJdbcParameters(
|
|||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
assert jdbcParameters.size() == 1;
|
assert jdbcParameters.size() == 1;
|
||||||
|
|
||||||
final Object bindableValue = naturalIdMapping().normalizeValue( naturalIdToLoad, session );
|
final Object bindableValue = naturalIdMapping().normalizeIncomingValue( naturalIdToLoad, session );
|
||||||
|
|
||||||
final SingularAttributeMapping attributeMapping = naturalIdMapping().getNaturalIdAttributes().get( 0 );
|
final SingularAttributeMapping attributeMapping = naturalIdMapping().getNaturalIdAttributes().get( 0 );
|
||||||
jdbcParamBindings.registerParametersForEachJdbcValue(
|
jdbcParamBindings.registerParametersForEachJdbcValue(
|
||||||
@ -75,7 +75,7 @@ protected void applyNaturalIdAsJdbcParameters(
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object resolveNaturalIdBindValue(Object naturalIdToLoad, SharedSessionContractImplementor session) {
|
protected Object resolveNaturalIdBindValue(Object naturalIdToLoad, SharedSessionContractImplementor session) {
|
||||||
return naturalIdMapping().normalizeValue( naturalIdToLoad, session );
|
return naturalIdMapping().normalizeIncomingValue( naturalIdToLoad, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -161,7 +161,7 @@ protected boolean isSimple() {
|
|||||||
public Object resolveNaturalIdToId(
|
public Object resolveNaturalIdToId(
|
||||||
Object naturalIdValue,
|
Object naturalIdValue,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
final Object bindValue = naturalIdMapping().normalizeValue( naturalIdValue, session );
|
final Object bindValue = naturalIdMapping().normalizeIncomingValue( naturalIdValue, session );
|
||||||
|
|
||||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||||
@ -103,4 +105,9 @@ default int forEachSelection(int offset, SelectionConsumer consumer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EntityMappingType findContainingEntityMapping();
|
EntityMappingType findContainingEntityMapping();
|
||||||
|
|
||||||
|
default boolean areEqual(Object one, Object other, SharedSessionContractImplementor session) {
|
||||||
|
// NOTE : deepEquals to account for arrays (compound natural-id)
|
||||||
|
return Objects.deepEquals( one, other );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
|
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
|
||||||
import org.hibernate.loader.ast.spi.NaturalIdLoader;
|
import org.hibernate.loader.ast.spi.NaturalIdLoader;
|
||||||
@ -23,6 +24,21 @@ public interface NaturalIdMapping extends VirtualModelPart {
|
|||||||
*/
|
*/
|
||||||
List<SingularAttributeMapping> getNaturalIdAttributes();
|
List<SingularAttributeMapping> getNaturalIdAttributes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the natural-id is immutable. This is the same as saying that none of
|
||||||
|
* the attributes are mutable
|
||||||
|
*/
|
||||||
|
boolean isImmutable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the natural-id value(s) we are about to flush to the database
|
||||||
|
*/
|
||||||
|
void verifyFlushState(
|
||||||
|
Object id,
|
||||||
|
Object[] currentState,
|
||||||
|
Object[] loadedState,
|
||||||
|
SharedSessionContractImplementor session);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default String getPartName() {
|
default String getPartName() {
|
||||||
return PART_NAME;
|
return PART_NAME;
|
||||||
@ -31,5 +47,40 @@ default String getPartName() {
|
|||||||
NaturalIdLoader getNaturalIdLoader();
|
NaturalIdLoader getNaturalIdLoader();
|
||||||
MultiNaturalIdLoader getMultiNaturalIdLoader();
|
MultiNaturalIdLoader getMultiNaturalIdLoader();
|
||||||
|
|
||||||
Object normalizeValue(Object incoming, SharedSessionContractImplementor session);
|
/**
|
||||||
|
* Given an array of "full entity state", extract the normalized natural id representation
|
||||||
|
*
|
||||||
|
* @param state The attribute state array
|
||||||
|
*
|
||||||
|
* @return The extracted natural id values. This is a normalized
|
||||||
|
*/
|
||||||
|
Object extractNaturalIdValues(Object[] state, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an entity instance, extract the normalized natural id representation
|
||||||
|
*
|
||||||
|
* @param entity The entity instance
|
||||||
|
*
|
||||||
|
* @return The extracted natural id values
|
||||||
|
*/
|
||||||
|
Object extractNaturalIdValues(Object entity, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize an incoming (user supplied) natural-id value.
|
||||||
|
*/
|
||||||
|
Object normalizeIncomingValue(Object incoming, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a natural id value(s) for the described natural-id based on the expected internal representation
|
||||||
|
*/
|
||||||
|
void validateInternalForm(Object naturalIdValue, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the hash-code of a natural-id value
|
||||||
|
*
|
||||||
|
* @param value The natural-id value
|
||||||
|
*
|
||||||
|
* @return The hash-code
|
||||||
|
*/
|
||||||
|
int calculateHashCode(Object value, SharedSessionContractImplementor session);
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,10 @@ public NavigableRole getNavigableRole() {
|
|||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntityMappingType getDeclaringType() {
|
||||||
|
return declaringType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityMappingType findContainingEntityMapping() {
|
public EntityMappingType findContainingEntityMapping() {
|
||||||
return declaringType;
|
return declaringType;
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
package org.hibernate.metamodel.mapping.internal;
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.loader.NaturalIdPostLoadListener;
|
import org.hibernate.loader.NaturalIdPostLoadListener;
|
||||||
import org.hibernate.loader.NaturalIdPreLoadListener;
|
import org.hibernate.loader.NaturalIdPreLoadListener;
|
||||||
@ -25,6 +28,7 @@
|
|||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.Clause;
|
import org.hibernate.sql.ast.Clause;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
@ -42,6 +46,7 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
|
|||||||
|
|
||||||
private final List<SingularAttributeMapping> attributes;
|
private final List<SingularAttributeMapping> attributes;
|
||||||
private final List<JdbcMapping> jdbcMappings;
|
private final List<JdbcMapping> jdbcMappings;
|
||||||
|
private final boolean immutable;
|
||||||
|
|
||||||
private final NaturalIdLoader<?> loader;
|
private final NaturalIdLoader<?> loader;
|
||||||
private final MultiNaturalIdLoader<?> multiLoader;
|
private final MultiNaturalIdLoader<?> multiLoader;
|
||||||
@ -54,11 +59,15 @@ public CompoundNaturalIdMapping(
|
|||||||
super( declaringType, cacheRegionName );
|
super( declaringType, cacheRegionName );
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
|
|
||||||
|
boolean anyMutable = false;
|
||||||
final List<JdbcMapping> jdbcMappings = new ArrayList<>();
|
final List<JdbcMapping> jdbcMappings = new ArrayList<>();
|
||||||
for ( int i = 0; i < attributes.size(); i++ ) {
|
for ( int i = 0; i < attributes.size(); i++ ) {
|
||||||
attributes.get( i ).forEachJdbcType( (index, jdbcMapping) -> jdbcMappings.add( jdbcMapping ) );
|
final SingularAttributeMapping attributeMapping = attributes.get( i );
|
||||||
|
attributeMapping.forEachJdbcType( (index, jdbcMapping) -> jdbcMappings.add( jdbcMapping ) );
|
||||||
|
anyMutable = anyMutable || attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( null ).isUpdatable();
|
||||||
}
|
}
|
||||||
this.jdbcMappings = jdbcMappings;
|
this.jdbcMappings = jdbcMappings;
|
||||||
|
this.immutable = ! anyMutable;
|
||||||
|
|
||||||
loader = new CompoundNaturalIdLoader<>(
|
loader = new CompoundNaturalIdLoader<>(
|
||||||
this,
|
this,
|
||||||
@ -70,11 +79,43 @@ public CompoundNaturalIdMapping(
|
|||||||
multiLoader = new MultiNaturalIdLoaderStandard<>( declaringType, creationProcess );
|
multiLoader = new MultiNaturalIdLoaderStandard<>( declaringType, creationProcess );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] extractNaturalIdValues(Object[] state, SharedSessionContractImplementor session) {
|
||||||
|
if ( state == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( state.length == attributes.size() ) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object[] values = new Object[ attributes.size() ];
|
||||||
|
|
||||||
|
for ( int i = 0; i <= attributes.size() - 1; i++ ) {
|
||||||
|
final SingularAttributeMapping attributeMapping = attributes.get( i );
|
||||||
|
final Object domainValue = state[ attributeMapping.getStateArrayPosition() ];
|
||||||
|
values[ i ] = attributeMapping.disassemble( domainValue, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] extractNaturalIdValues(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
final Object[] values = new Object[ attributes.size() ];
|
||||||
|
|
||||||
|
for ( int i = 0; i < attributes.size(); i++ ) {
|
||||||
|
values[i] = attributes.get( i ).getPropertyAccess().getGetter().get( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( "rawtypes" )
|
@SuppressWarnings( "rawtypes" )
|
||||||
public Object normalizeValue(Object incoming, SharedSessionContractImplementor session) {
|
public Object[] normalizeIncomingValue(Object incoming, SharedSessionContractImplementor session) {
|
||||||
if ( incoming instanceof Object[] ) {
|
if ( incoming instanceof Object[] ) {
|
||||||
return incoming;
|
return (Object[]) incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( incoming instanceof Map ) {
|
if ( incoming instanceof Map ) {
|
||||||
@ -90,11 +131,95 @@ public Object normalizeValue(Object incoming, SharedSessionContractImplementor s
|
|||||||
throw new UnsupportedOperationException( "Do not know how to normalize compound natural-id value : " + incoming );
|
throw new UnsupportedOperationException( "Do not know how to normalize compound natural-id value : " + incoming );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateInternalForm(Object naturalIdValue, SharedSessionContractImplementor session) {
|
||||||
|
if ( naturalIdValue == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be an array, with a size equal to the number of attributes making up this compound natural-id
|
||||||
|
if ( naturalIdValue instanceof Object[] ) {
|
||||||
|
final Object[] values = (Object[]) naturalIdValue;
|
||||||
|
if ( values.length != attributes.size() ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Natural-id value [" + naturalIdValue + "] did not contain the expected number of elements ["
|
||||||
|
+ attributes.size() + "]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException( "Natural-id value [" + naturalIdValue + "] was not an array as expected" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int calculateHashCode(Object value, SharedSessionContractImplementor session) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void verifyFlushState(Object id, Object[] currentState, Object[] loadedState, SharedSessionContractImplementor session) {
|
||||||
|
if ( ! immutable ) {
|
||||||
|
// EARLY EXIT!!!
|
||||||
|
// the natural id is mutable (!immutable), no need to do the checks
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
|
final EntityPersister persister = getDeclaringType().getEntityPersister();
|
||||||
|
|
||||||
|
final Object[] naturalId = extractNaturalIdValues( currentState, session );
|
||||||
|
|
||||||
|
final Object snapshot = loadedState == null
|
||||||
|
? persistenceContext.getNaturalIdSnapshot( id, persister )
|
||||||
|
: persistenceContext.getNaturalIdHelper().extractNaturalIdValues( loadedState, persister );
|
||||||
|
final Object[] previousNaturalId = (Object[]) snapshot;
|
||||||
|
|
||||||
|
assert naturalId.length == getNaturalIdAttributes().size();
|
||||||
|
assert previousNaturalId.length == naturalId.length;
|
||||||
|
|
||||||
|
for ( int i = 0; i < getNaturalIdAttributes().size(); i++ ) {
|
||||||
|
final SingularAttributeMapping attributeMapping = getNaturalIdAttributes().get( i );
|
||||||
|
|
||||||
|
final boolean updatable = attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( persister ).isUpdatable();
|
||||||
|
if ( updatable ) {
|
||||||
|
// property is updatable (mutable), there is nothing to check
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object currentValue = naturalId[ i ];
|
||||||
|
final Object previousValue = previousNaturalId[ i ];
|
||||||
|
|
||||||
|
if ( ! attributeMapping.areEqual( currentValue, previousValue, session ) ) {
|
||||||
|
throw new HibernateException(
|
||||||
|
String.format(
|
||||||
|
"An immutable attribute [%s] within compound natural identifier of entity %s was altered from `%s` to `%s`",
|
||||||
|
attributeMapping.getAttributeName(),
|
||||||
|
persister.getEntityName(),
|
||||||
|
previousValue,
|
||||||
|
currentValue
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areEqual(Object one, Object other, SharedSessionContractImplementor session) {
|
||||||
|
return Arrays.equals( (Object[]) one, (Object[]) other );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SingularAttributeMapping> getNaturalIdAttributes() {
|
public List<SingularAttributeMapping> getNaturalIdAttributes() {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isImmutable() {
|
||||||
|
return immutable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NaturalIdLoader<?> getNaturalIdLoader() {
|
public NaturalIdLoader<?> getNaturalIdLoader() {
|
||||||
return loader;
|
return loader;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.loader.NaturalIdPostLoadListener;
|
import org.hibernate.loader.NaturalIdPostLoadListener;
|
||||||
import org.hibernate.loader.NaturalIdPreLoadListener;
|
import org.hibernate.loader.NaturalIdPreLoadListener;
|
||||||
@ -24,6 +26,7 @@
|
|||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.Clause;
|
import org.hibernate.sql.ast.Clause;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
@ -38,6 +41,8 @@
|
|||||||
public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
public class SimpleNaturalIdMapping extends AbstractNaturalIdMapping {
|
||||||
private final SingularAttributeMapping attribute;
|
private final SingularAttributeMapping attribute;
|
||||||
|
|
||||||
|
private final boolean immutable;
|
||||||
|
|
||||||
private final SimpleNaturalIdLoader<?> loader;
|
private final SimpleNaturalIdLoader<?> loader;
|
||||||
private final MultiNaturalIdLoader<?> multiLoader;
|
private final MultiNaturalIdLoader<?> multiLoader;
|
||||||
|
|
||||||
@ -49,6 +54,10 @@ public SimpleNaturalIdMapping(
|
|||||||
super( declaringType, cacheRegionName );
|
super( declaringType, cacheRegionName );
|
||||||
this.attribute = attribute;
|
this.attribute = attribute;
|
||||||
|
|
||||||
|
this.immutable = ! attribute.getAttributeMetadataAccess()
|
||||||
|
.resolveAttributeMetadata( null )
|
||||||
|
.isUpdatable();
|
||||||
|
|
||||||
this.loader = new SimpleNaturalIdLoader<>(
|
this.loader = new SimpleNaturalIdLoader<>(
|
||||||
this,
|
this,
|
||||||
NaturalIdPreLoadListener.NO_OP,
|
NaturalIdPreLoadListener.NO_OP,
|
||||||
@ -60,12 +69,77 @@ public SimpleNaturalIdMapping(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object normalizeValue(Object incoming, SharedSessionContractImplementor session) {
|
public void verifyFlushState(Object id, Object[] currentState, Object[] loadedState, SharedSessionContractImplementor session) {
|
||||||
return normalizeValue( incoming );
|
if ( ! immutable ) {
|
||||||
|
// EARLY EXIT!!!
|
||||||
|
// the natural id is mutable (!immutable), no need to do the checks
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
|
final EntityPersister persister = getDeclaringType().getEntityPersister();
|
||||||
|
|
||||||
|
final Object naturalId = extractNaturalIdValues( currentState, session );
|
||||||
|
final Object snapshot = loadedState == null
|
||||||
|
? persistenceContext.getNaturalIdSnapshot( id, persister )
|
||||||
|
: persistenceContext.getNaturalIdHelper().extractNaturalIdValues( loadedState, persister );
|
||||||
|
|
||||||
|
if ( ! areEqual( naturalId, snapshot, session ) ) {
|
||||||
|
throw new HibernateException(
|
||||||
|
String.format(
|
||||||
|
"An immutable natural identifier of entity %s was altered from `%s` to `%s`",
|
||||||
|
persister.getEntityName(),
|
||||||
|
snapshot,
|
||||||
|
naturalId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object extractNaturalIdValues(Object[] state, SharedSessionContractImplementor session) {
|
||||||
|
return state[ attribute.getStateArrayPosition() ];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object extractNaturalIdValues(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
return attribute.getPropertyAccess().getGetter().get( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateInternalForm(Object naturalIdValue, SharedSessionContractImplementor session) {
|
||||||
|
if ( naturalIdValue == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( naturalIdValue.getClass().isArray() ) {
|
||||||
|
// be flexible
|
||||||
|
final Object[] values = (Object[]) naturalIdValue;
|
||||||
|
if ( values.length == 1 ) {
|
||||||
|
naturalIdValue = values[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! getJavaTypeDescriptor().getJavaType().isInstance( naturalIdValue ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Incoming natural-id value [" + naturalIdValue + "] is not of expected type ["
|
||||||
|
+ getJavaTypeDescriptor().getJavaType().getName() + "]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int calculateHashCode(Object value, SharedSessionContractImplementor session) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object normalizeIncomingValue(Object incoming, SharedSessionContractImplementor session) {
|
||||||
|
return normalizeIncomingValue( incoming );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( "rawtypes" )
|
@SuppressWarnings( "rawtypes" )
|
||||||
public Object normalizeValue(Object naturalIdToLoad) {
|
public Object normalizeIncomingValue(Object naturalIdToLoad) {
|
||||||
if ( naturalIdToLoad instanceof Map ) {
|
if ( naturalIdToLoad instanceof Map ) {
|
||||||
final Map valueMap = (Map) naturalIdToLoad;
|
final Map valueMap = (Map) naturalIdToLoad;
|
||||||
assert valueMap.size() == 1;
|
assert valueMap.size() == 1;
|
||||||
@ -101,6 +175,11 @@ public List<SingularAttributeMapping> getNaturalIdAttributes() {
|
|||||||
return Collections.singletonList( attribute );
|
return Collections.singletonList( attribute );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isImmutable() {
|
||||||
|
return immutable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MappingType getPartMappingType() {
|
public MappingType getPartMappingType() {
|
||||||
return attribute.getPartMappingType();
|
return attribute.getPartMappingType();
|
||||||
|
@ -5010,7 +5010,7 @@ private void handleNaturalIdReattachment(Object entity, SharedSessionContractImp
|
|||||||
|
|
||||||
// for reattachment of mutable natural-ids, we absolutely positively have to grab the snapshot from the
|
// for reattachment of mutable natural-ids, we absolutely positively have to grab the snapshot from the
|
||||||
// database, because we have no other way to know if the state changed while detached.
|
// database, because we have no other way to know if the state changed while detached.
|
||||||
final Object[] naturalIdSnapshot;
|
final Object naturalIdSnapshot;
|
||||||
final Object[] entitySnapshot = persistenceContext.getDatabaseSnapshot( id, this );
|
final Object[] entitySnapshot = persistenceContext.getDatabaseSnapshot( id, this );
|
||||||
if ( entitySnapshot == StatefulPersistenceContext.NO_ROW ) {
|
if ( entitySnapshot == StatefulPersistenceContext.NO_ROW ) {
|
||||||
naturalIdSnapshot = null;
|
naturalIdSnapshot = null;
|
||||||
@ -5019,12 +5019,9 @@ private void handleNaturalIdReattachment(Object entity, SharedSessionContractImp
|
|||||||
naturalIdSnapshot = naturalIdHelper.extractNaturalIdValues( entitySnapshot, this );
|
naturalIdSnapshot = naturalIdHelper.extractNaturalIdValues( entitySnapshot, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
naturalIdHelper.removeSharedNaturalIdCrossReference( this, id, naturalIdSnapshot );
|
naturalIdHelper.removeSharedResolution( this, id, naturalIdSnapshot );
|
||||||
naturalIdHelper.manageLocalNaturalIdCrossReference(
|
naturalIdHelper.manageLocalResolution(
|
||||||
this,
|
id, naturalIdHelper.extractNaturalIdValues( entity, this ), this,
|
||||||
id,
|
|
||||||
naturalIdHelper.extractNaturalIdValues( entity, this ),
|
|
||||||
naturalIdSnapshot,
|
|
||||||
CachedNaturalIdValueSource.UPDATE
|
CachedNaturalIdValueSource.UPDATE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -659,7 +659,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( entityDescriptor.getNaturalIdMapping() != null ) {
|
if ( entityDescriptor.getNaturalIdMapping() != null ) {
|
||||||
persistenceContext.getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad(
|
persistenceContext.getNaturalIdHelper().cacheResolutionFromLoad(
|
||||||
entityDescriptor,
|
entityDescriptor,
|
||||||
entityIdentifier,
|
entityIdentifier,
|
||||||
persistenceContext.getNaturalIdHelper()
|
persistenceContext.getNaturalIdHelper()
|
||||||
|
@ -74,7 +74,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
|
|||||||
assertEquals(key.hashCode(), keyClone.hashCode());
|
assertEquals(key.hashCode(), keyClone.hashCode());
|
||||||
assertEquals(key.toString(), keyClone.toString());
|
assertEquals(key.toString(), keyClone.toString());
|
||||||
assertEquals(key.getEntityName(), keyClone.getEntityName());
|
assertEquals(key.getEntityName(), keyClone.getEntityName());
|
||||||
assertArrayEquals(key.getNaturalIdValues(), keyClone.getNaturalIdValues());
|
assertEquals(key.getNaturalIdValues(), keyClone.getNaturalIdValues());
|
||||||
assertEquals(key.getTenantId(), keyClone.getTenantId());
|
assertEquals(key.getTenantId(), keyClone.getTenantId());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user