HHH-2879 - initial clean implementation with no caching

This commit is contained in:
Steve Ebersole 2012-01-12 15:15:01 -06:00
parent e01ea2ecf8
commit fb3566b467
10 changed files with 317 additions and 304 deletions

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,11 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate;
/**
* Contract for resolving an entity-name from a given entity instance.
*

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -29,46 +29,40 @@ import java.io.Serializable;
* Loads an entity by its primary identifier
*
* @author Eric Dalquist
* @version $Revision$
* @author Steve Ebersole
*/
public interface IdentifierLoadAccess<T> {
public interface IdentifierLoadAccess {
/**
* Set the {@link LockOptions} to use when retrieving the entity.
* Specify the {@link LockOptions} to use when retrieving the entity.
*
* @param lockOptions The lock options to use.
*
* @return {@code this}, for method chaining
*/
public IdentifierLoadAccess<T> with(LockOptions lockOptions);
public IdentifierLoadAccess with(LockOptions lockOptions);
/**
* Return the persistent instance of the given entity class with the given identifier,
* assuming that the instance exists. This method might return a proxied instance that
* is initialized on-demand, when a non-identifier method is accessed. <br>
* <br>
* You should not use this method to determine if an instance exists (use <tt>get()</tt> instead). Use this only to
* retrieve an instance that you assume exists, where non-existence
* would be an actual error. <br>
* <br>
* Due to the nature of the proxy functionality the return type of this method cannot use
* the generic type.
*
* @param theClass
* a persistent class
* @param id
* a valid identifier of an existing persistent instance of the class
* Return the persistent instance with the given identifier, assuming that the instance exists. This method
* might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.
*
* You should not use this method to determine if an instance exists; to check for existence, use {@link #load}
* instead. Use this only to retrieve an instance that you assume exists, where non-existence would be an
* actual error.
*
* @param id The identifier for which to obtain a reference
*
* @return the persistent instance or proxy
* @throws HibernateException
*/
public Object getReference(Serializable id);
/**
* Return the persistent instance of the given entity class with the given identifier,
* or null if there is no such persistent instance. (If the instance is already associated
* with the session, return that instance. This method never returns an uninitialized instance.)
*
* @param clazz
* a persistent class
* @param id
* an identifier
* @return a persistent instance or null
* @throws HibernateException
* Return the persistent instance with the given identifier, or null if there is no such persistent instance.
* If the instance is already associated with the session, return that instance, initializing it if needed. This
* method never returns an uninitialized instance.
*
* @param id The identifier
*
* @return The persistent instance or {@code null}
*/
public Object load(Serializable id);
}

View File

@ -39,16 +39,34 @@ public class LockOptions implements Serializable {
* NONE represents LockMode.NONE (timeout + scope do not apply)
*/
public static final LockOptions NONE = new LockOptions(LockMode.NONE);
/**
* READ represents LockMode.READ (timeout + scope do not apply)
*/
public static final LockOptions READ = new LockOptions(LockMode.READ);
/**
* UPGRADE represents LockMode.UPGRADE (will wait forever for lock and
* scope of false meaning only entity is locked)
*/
public static final LockOptions UPGRADE = new LockOptions(LockMode.UPGRADE);
/**
* Indicates that the database should not wait at all to acquire the pessimistic lock.
* @see #getTimeOut
*/
public static final int NO_WAIT = 0;
/**
* Indicates that there is no timeout for the acquisition.
* @see #getTimeOut
*/
public static final int WAIT_FOREVER = -1;
private LockMode lockMode = LockMode.NONE;
private int timeout = WAIT_FOREVER;
private Map aliasSpecificLockModes = null; //initialize lazily as LockOptions is frequently created without needing this
public LockOptions() {
}
@ -56,7 +74,6 @@ public class LockOptions implements Serializable {
this.lockMode = lockMode;
}
private LockMode lockMode = LockMode.NONE;
/**
* Retrieve the overall lock mode in effect for this set of options.
@ -83,7 +100,6 @@ public class LockOptions implements Serializable {
return this;
}
private Map aliasSpecificLockModes = null; //initialize lazily as LockOptions is frequently created without needing this
/**
* Specify the {@link LockMode} to be used for a specific query alias.
@ -167,19 +183,6 @@ public class LockOptions implements Serializable {
return aliasSpecificLockModes.entrySet().iterator();
}
/**
* Indicates that the database should not wait at all to acquire the pessimistic lock.
* @see #getTimeOut
*/
public static final int NO_WAIT = 0;
/**
* Indicates that there is no timeout for the acquisition.
* @see #getTimeOut
*/
public static final int WAIT_FOREVER = -1;
private int timeout = WAIT_FOREVER;
/**
* Retrieve the current timeout setting.
* <p/>

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -27,37 +27,48 @@ package org.hibernate;
* Loads an entity by its natural identifier
*
* @author Eric Dalquist
* @author Steve Ebersole
*
* @see org.hibernate.annotations.NaturalId
*/
public interface NaturalIdLoadAccess<T> {
public interface NaturalIdLoadAccess {
/**
* Set the {@link LockOptions} to use when retrieving the entity.
* Specify the {@link LockOptions} to use when retrieving the entity.
*
* @param lockOptions The lock options to use.
*
* @return {@code this}, for method chaining
*/
public NaturalIdLoadAccess<T> with(LockOptions lockOptions);
public NaturalIdLoadAccess with(LockOptions lockOptions);
/**
* Add a NaturalId attribute value.
*
* @param attributeName
* The entity attribute name that is marked as a NaturalId
* @param value
* The value of the attribute
* @param attributeName The entity attribute name that is marked as a NaturalId
* @param value The value of the attribute
*
* @return {@code this}, for method chaining
*/
public NaturalIdLoadAccess<T> using(String attributeName, Object value);
public NaturalIdLoadAccess using(String attributeName, Object value);
/**
* Same behavior as {@link Session#load(Class, java.io.Serializable)}
*
* @return The entity
* @throws HibernateException
* if the entity does not exist
* Return the persistent instance with the natural id value(s) defined by the call(s) to {@link #using}. This
* method might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.
*
* You should not use this method to determine if an instance exists; to check for existence, use {@link #load}
* instead. Use this only to retrieve an instance that you assume exists, where non-existence would be an
* actual error.
*
* @return the persistent instance or proxy
*/
public Object getReference();
/**
* Same behavior as {@link Session#get(Class, java.io.Serializable)}
*
* @return The entity or null if it does not exist
* Return the persistent instance with the natural id value(s) defined by the call(s) to {@link #using}, or
* {@code null} if there is no such persistent instance. If the instance is already associated with the session,
* return that instance, initializing it if needed. This method never returns an uninitialized instance.
*
* @return The persistent instance or {@code null}
*/
public Object load();

View File

@ -772,48 +772,52 @@ public interface Session extends SharedSessionContract {
public String getEntityName(Object object) throws HibernateException;
/**
* Create an {@link IdentifierLoadAccess} instance to retrieve the specified entity by
* Create an {@link IdentifierLoadAccess} instance to retrieve the specified entity type by
* primary key.
*
* @param entityName
* The name of the entity that will be retrieved
* @throws HibernateException
* If the specified entity name is not found
* @param entityName The entity name of the entity type to be retrieved
*
* @return load delegate for loading the specified entity type by primary key
*
* @throws HibernateException If the specified entity name cannot be resolved as an entity name
*/
public IdentifierLoadAccess<Object> byId(String entityName);
public IdentifierLoadAccess byId(String entityName);
/**
* Create an {@link IdentifierLoadAccess} instance to retrieve the specified entity by
* primary key.
*
* @param entityClass
* The type of the entity that will be retrieved
* @throws HibernateException
* If the specified Class is not an entity
*
* @param entityClass The entity type to be retrieved
*
* @return load delegate for loading the specified entity type by primary key
*
* @throws HibernateException If the specified Class cannot be resolved as a mapped entity
*/
public <T> IdentifierLoadAccess<T> byId(Class<T> entityClass);
public IdentifierLoadAccess byId(Class entityClass);
/**
* Create an {@link NaturalIdLoadAccess} instance to retrieve the specified entity by
* its natural id.
*
* @param entityName
* The name of the entity that will be retrieved
* @throws HibernateException
* If the specified entity name is not found or if the entity does not have a natural id specified
* @param entityName The entity name of the entity type to be retrieved
*
* @return load delegate for loading the specified entity type by natural id
*
* @throws HibernateException If the specified entity name cannot be resolved as an entity name
*/
public NaturalIdLoadAccess<Object> byNaturalId(String entityName);
public NaturalIdLoadAccess byNaturalId(String entityName);
/**
* Create an {@link NaturalIdLoadAccess} instance to retrieve the specified entity by
* its natural id.
*
* @param entityClass
* The type of the entity that will be retrieved
* @throws HibernateException
* If the specified Class is not an entity or if the entity does not have a natural id specified
* @param entityClass The entity type to be retrieved
*
* @return load delegate for loading the specified entity type by natural id
*
* @throws HibernateException If the specified Class cannot be resolved as a mapped entity
*/
public <T> NaturalIdLoadAccess<T> byNaturalId(Class<T> entityClass);
public NaturalIdLoadAccess byNaturalId(Class entityClass);
/**
* Enable the named filter for this current session.

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -24,19 +24,15 @@
package org.hibernate.event.internal;
import java.io.Serializable;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.event.spi.ResolveNaturalIdEvent;
import org.hibernate.event.spi.ResolveNaturalIdEventListener;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.tuple.StandardProperty;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.jboss.logging.Logger;
/**
* Defines the default load event listeners used by hibernate for loading entities
@ -44,56 +40,21 @@ import org.jboss.logging.Logger;
*
* @author Eric Dalquist
*/
public class DefaultResolveNaturalIdEventListener extends AbstractLockUpgradeEventListener implements
ResolveNaturalIdEventListener {
public class DefaultResolveNaturalIdEventListener
extends AbstractLockUpgradeEventListener
implements ResolveNaturalIdEventListener {
public static final Object REMOVED_ENTITY_MARKER = new Object();
public static final Object INCONSISTENT_RTN_CLASS_MARKER = new Object();
public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class,
DefaultResolveNaturalIdEventListener.class.getName() );
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
DefaultResolveNaturalIdEventListener.class.getName()
);
/*
* (non-Javadoc)
*
* @see org.hibernate.event.spi.ResolveNaturalIdEventListener#onResolveNaturalId(org.hibernate.event.spi.
* ResolveNaturalIdEvent)
*/
@Override
public void onResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException {
final SessionImplementor source = event.getSession();
EntityPersister persister = source.getFactory().getEntityPersister( event.getEntityClassName() );
if ( persister == null ) {
throw new HibernateException( "Unable to locate persister: " + event.getEntityClassName() );
}
// Verify that the entity has a natural id and that the properties match up with the event.
final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
final int[] naturalIdentifierProperties = entityMetamodel.getNaturalIdentifierProperties();
if ( naturalIdentifierProperties == null || naturalIdentifierProperties.length == 0 ) {
throw new HibernateException( event.getEntityClassName() + " does not have a natural id" );
}
final Map<String, Object> naturalIdParams = event.getNaturalId();
if ( naturalIdentifierProperties.length != naturalIdParams.size() ) {
throw new HibernateException( event.getEntityClassName() + " has " + naturalIdentifierProperties.length
+ " properties in its natural id but " + naturalIdParams.size() + " properties were specified: "
+ naturalIdParams );
}
final StandardProperty[] properties = entityMetamodel.getProperties();
for ( int idPropIdx = 0; idPropIdx < naturalIdentifierProperties.length; idPropIdx++ ) {
final StandardProperty property = properties[naturalIdentifierProperties[idPropIdx]];
final String name = property.getName();
if ( !naturalIdParams.containsKey( name ) ) {
throw new HibernateException( event.getEntityClassName() + " natural id property " + name
+ " is missing from the map of natural id parameters: " + naturalIdParams );
}
}
final Serializable entityId = doResolveNaturalId( event, persister );
final Serializable entityId = resolveNaturalId( event );
event.setEntityId( entityId );
}
@ -103,74 +64,78 @@ public class DefaultResolveNaturalIdEventListener extends AbstractLockUpgradeEve
* an attempt is made to locate it in second-level cache. Lastly, an
* attempt is made to load it directly from the datasource.
*
* @param event
* The load event
* @param persister
* The persister for the entity being requested for load
* @param keyToLoad
* The EntityKey representing the entity to be loaded.
* @param options
* The load options.
* @param event The load event
*
* @return The loaded entity, or null.
*/
protected Serializable doResolveNaturalId(final ResolveNaturalIdEvent event, final EntityPersister persister) {
protected Serializable resolveNaturalId(final ResolveNaturalIdEvent event) {
final EntityPersister persister = event.getEntityPersister();
if ( LOG.isTraceEnabled() )
LOG.trace( "Attempting to resolve: "
+ MessageHelper.infoString( persister, event.getNaturalId(), event.getSession().getFactory() ) );
if ( LOG.isTraceEnabled() ) {
LOG.trace(
"Attempting to resolve: " +
MessageHelper.infoString(
persister, event.getNaturalIdValues(), event.getSession().getFactory()
)
);
}
Serializable entityId = loadFromSessionCache( event, persister );
Serializable entityId = resolveFromSessionCache( event );
if ( entityId == REMOVED_ENTITY_MARKER ) {
LOG.debugf( "Load request found matching entity in context, but it is scheduled for removal; returning null" );
LOG.debug( "Load request found matching entity in context, but it is scheduled for removal; returning null" );
return null;
}
if ( entityId == INCONSISTENT_RTN_CLASS_MARKER ) {
LOG.debugf( "Load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null" );
LOG.debug(
"Load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null"
);
return null;
}
if ( entityId != null ) {
if ( LOG.isTraceEnabled() )
LOG.trace( "Resolved object in session cache: "
+ MessageHelper.infoString( persister, event.getNaturalId(), event.getSession().getFactory() ) );
if ( LOG.isTraceEnabled() ) {
LOG.trace(
"Resolved object in session cache: " +
MessageHelper.infoString(
persister, event.getNaturalIdValues(), event.getSession().getFactory()
)
);
}
return entityId;
}
entityId = loadFromSecondLevelCache( event, persister );
entityId = loadFromSecondLevelCache( event );
if ( entityId != null ) {
if ( LOG.isTraceEnabled() )
LOG.trace( "Resolved object in second-level cache: "
+ MessageHelper.infoString( persister, event.getNaturalId(), event.getSession().getFactory() ) );
if ( LOG.isTraceEnabled() ) {
LOG.trace(
"Resolved object in second-level cache: " +
MessageHelper.infoString(
persister, event.getNaturalIdValues(), event.getSession().getFactory()
)
);
}
return entityId;
}
if ( LOG.isTraceEnabled() )
LOG.trace( "Object not resolved in any cache: "
+ MessageHelper.infoString( persister, event.getNaturalId(), event.getSession().getFactory() ) );
if ( LOG.isTraceEnabled() ) {
LOG.trace(
"Object not resolved in any cache: " +
MessageHelper.infoString(
persister, event.getNaturalIdValues(), event.getSession().getFactory()
)
);
}
return loadFromDatasource( event, persister );
return loadFromDatasource( event );
}
/**
* Attempts to locate the entity in the session-level cache.
* <p/>
* If allowed to return nulls, then if the entity happens to be found in the session cache, we check the entity type
* for proper handling of entity hierarchies.
* <p/>
* If checkDeleted was set to true, then if the entity is found in the session-level cache, it's current status
* within the session cache is checked to see if it has previously been scheduled for deletion.
* Attempts to resolve the entity id corresponding to the event's natural id values from the session
*
* @param event
* The load event
* @param keyToLoad
* The EntityKey representing the entity to be loaded.
* @param options
* The load options.
* @param event The load event
*
* @return The entity from the session-level cache, or null.
* @throws HibernateException
* Generally indicates problems applying a lock-mode.
*/
protected Serializable loadFromSessionCache(final ResolveNaturalIdEvent event, final EntityPersister persister)
throws HibernateException {
protected Serializable resolveFromSessionCache(final ResolveNaturalIdEvent event) {
// SessionImplementor session = event.getSession();
// Object old = session.getEntityUsingInterceptor( keyToLoad );
//
@ -199,15 +164,11 @@ public class DefaultResolveNaturalIdEventListener extends AbstractLockUpgradeEve
/**
* Attempts to load the entity from the second-level cache.
*
* @param event
* The load event
* @param persister
* The persister for the entity being requested for load
* @param options
* The load options.
* @param event The event
*
* @return The entity from the second-level cache, or null.
*/
protected Serializable loadFromSecondLevelCache(final ResolveNaturalIdEvent event, final EntityPersister persister) {
protected Serializable loadFromSecondLevelCache(final ResolveNaturalIdEvent event) {
// final SessionImplementor source = event.getSession();
//
@ -219,7 +180,7 @@ public class DefaultResolveNaturalIdEventListener extends AbstractLockUpgradeEve
// final SessionFactoryImplementor factory = source.getFactory();
//
// final CacheKey ck = source.generateCacheKey(
// event.getNaturalId(),
// event.getNaturalIdValues(),
// persister.getIdentifierType(),
// persister.getRootEntityName()
// );
@ -257,19 +218,15 @@ public class DefaultResolveNaturalIdEventListener extends AbstractLockUpgradeEve
* Performs the process of loading an entity from the configured
* underlying datasource.
*
* @param event
* The load event
* @param persister
* The persister for the entity being requested for load
* @param keyToLoad
* The EntityKey representing the entity to be loaded.
* @param options
* The load options.
* @param event The load event
*
* @return The object loaded from the datasource, or null if not found.
*/
protected Serializable loadFromDatasource(final ResolveNaturalIdEvent event, final EntityPersister persister) {
final SessionImplementor source = event.getSession();
return persister.loadEntityIdByNaturalId( event.getNaturalId(), event.getLockOptions(), event.getSession() );
protected Serializable loadFromDatasource(final ResolveNaturalIdEvent event) {
return event.getEntityPersister().loadEntityIdByNaturalId(
event.getNaturalIdValues(),
event.getLockOptions(),
event.getSession()
);
}
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -29,29 +29,39 @@ import java.util.Map;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.persister.entity.EntityPersister;
/**
* Defines an event class for the resolving of an entity id from the entity's natural-id
*
* @author Eric Dalquist
* @author Steve Ebersole
*/
public class ResolveNaturalIdEvent extends AbstractEvent {
public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;
private Map<String, Object> naturalId;
private LockOptions lockOptions;
private String entityClassName;
private final EntityPersister entityPersister;
private final Map<String, Object> naturalIdValues;
private final LockOptions lockOptions;
private Serializable entityId;
public ResolveNaturalIdEvent(Map<String, Object> naturalId, String entityClassName, EventSource source) {
this( naturalId, entityClassName, new LockOptions(), source );
public ResolveNaturalIdEvent(Map<String, Object> naturalIdValues, EntityPersister entityPersister, EventSource source) {
this( naturalIdValues, entityPersister, new LockOptions(), source );
}
public ResolveNaturalIdEvent(Map<String, Object> naturalId, String entityClassName, LockOptions lockOptions,
public ResolveNaturalIdEvent(
Map<String, Object> naturalIdValues,
EntityPersister entityPersister,
LockOptions lockOptions,
EventSource source) {
super( source );
if ( naturalId == null || naturalId.isEmpty() ) {
if ( entityPersister == null ) {
throw new IllegalArgumentException( "EntityPersister is required for loading" );
}
if ( naturalIdValues == null || naturalIdValues.isEmpty() ) {
throw new IllegalArgumentException( "id to load is required for loading" );
}
@ -62,24 +72,25 @@ public class ResolveNaturalIdEvent extends AbstractEvent {
lockOptions.setLockMode( DEFAULT_LOCK_MODE );
}
this.naturalId = naturalId;
this.entityClassName = entityClassName;
this.entityPersister = entityPersister;
this.naturalIdValues = naturalIdValues;
this.lockOptions = lockOptions;
}
public Map<String, Object> getNaturalId() {
return Collections.unmodifiableMap( naturalId );
public Map<String, Object> getNaturalIdValues() {
return Collections.unmodifiableMap( naturalIdValues );
}
public void setNaturalId(Map<String, Object> naturalId) {
this.naturalId = naturalId;
public EntityPersister getEntityPersister() {
return entityPersister;
}
public String getEntityClassName() {
return entityClassName;
return getEntityPersister().getEntityName();
}
public void setEntityClassName(String entityClassName) {
this.entityClassName = entityClassName;
public LockOptions getLockOptions() {
return lockOptions;
}
public Serializable getEntityId() {
@ -89,12 +100,4 @@ public class ResolveNaturalIdEvent extends AbstractEvent {
public void setEntityId(Serializable entityId) {
this.entityId = entityId;
}
public LockOptions getLockOptions() {
return lockOptions;
}
public void setLockOptions(LockOptions lockOptions) {
this.lockOptions = lockOptions;
}
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
@ -31,15 +31,16 @@ import org.hibernate.HibernateException;
* Defines the contract for handling of resolve natural id events generated from a session.
*
* @author Eric Dalquist
* @author Steve Ebersole
*/
public interface ResolveNaturalIdEventListener extends Serializable {
/**
* Handle the given resolve natural id event.
*
* @param event
* The resolve natural id event to be handled.
* @throws HibernateException
* @param event The resolve natural id event to be handled.
*
* @throws HibernateException Indicates a problem resolving natural id to primary key
*/
public void onResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException;

View File

@ -366,7 +366,8 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
try {
if (ois != null) ois.close();
}
catch (IOException ex) {}
catch (IOException ignore) {
}
}
}
@ -385,7 +386,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
try {
oos.close();
}
catch( IOException ex ) {
catch( IOException ignore ) {
//ignore
}
}
@ -413,7 +414,8 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
try {
if (ois != null) ois.close();
}
catch (IOException ex) {}
catch (IOException ignore) {
}
}
}
@ -495,6 +497,8 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
* if there is not, flush if necessary, make sure the connection has
* been committed (if it is not in autocommit mode) and run the after
* completion processing
*
* @param success Was the operation a success
*/
public void afterOperation(boolean success) {
if ( ! transactionCoordinator.isTransactionInProgress() ) {
@ -891,7 +895,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
public Object load(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
return this.byId( entityClass ).with( lockMode ).getReference( id );
return this.byId( entityClass ).with( new LockOptions( lockMode ) ).getReference( id );
}
public Object load(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
@ -899,7 +903,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
return this.byId( entityName ).with( lockMode ).getReference( id );
return this.byId( entityName ).with( new LockOptions( lockMode ) ).getReference( id );
}
public Object load(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException {
@ -907,7 +911,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
public Object get(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
return this.byId( entityClass ).with( lockMode ).load( id );
return this.byId( entityClass ).with( new LockOptions( lockMode ) ).load( id );
}
public Object get(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException {
@ -915,7 +919,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
return this.byId( entityName ).with( lockMode ).load( id );
return this.byId( entityName ).with( new LockOptions( lockMode ) ).load( id );
}
public Object get(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException {
@ -923,23 +927,23 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
@Override
public IdentifierLoadAccessImpl<Object> byId(String entityName) {
return new IdentifierLoadAccessImpl<Object>( entityName, Object.class );
public IdentifierLoadAccessImpl byId(String entityName) {
return new IdentifierLoadAccessImpl( entityName );
}
@Override
public <T> IdentifierLoadAccessImpl<T> byId(Class<T> entityClass) {
return new IdentifierLoadAccessImpl<T>( entityClass.getName(), entityClass );
public IdentifierLoadAccessImpl byId(Class entityClass) {
return new IdentifierLoadAccessImpl( entityClass );
}
@Override
public NaturalIdLoadAccess<Object> byNaturalId(String entityName) {
return new NaturalIdLoadAccessImpl<Object>( entityName, Object.class );
public NaturalIdLoadAccess byNaturalId(String entityName) {
return new NaturalIdLoadAccessImpl( entityName );
}
@Override
public <T> NaturalIdLoadAccess<T> byNaturalId(Class<T> entityClass) {
return new NaturalIdLoadAccessImpl<T>( entityClass.getName(), entityClass );
public NaturalIdLoadAccess byNaturalId(Class entityClass) {
return new NaturalIdLoadAccessImpl( entityClass );
}
private void fireLoad(LoadEvent event, LoadType loadType) {
@ -2168,47 +2172,45 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
}
private class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
private final String entityName;
private final Class<T> entityClass;
private class IdentifierLoadAccessImpl implements IdentifierLoadAccess {
private final EntityPersister entityPersister;
private LockOptions lockOptions;
private IdentifierLoadAccessImpl(String entityName, Class<T> entityClass) {
this.entityName = entityName;
this.entityClass = entityClass;
private IdentifierLoadAccessImpl(EntityPersister entityPersister) {
this.entityPersister = entityPersister;
}
private IdentifierLoadAccessImpl(String entityName) {
this( factory.getEntityPersister( entityName ) );
if ( entityPersister == null ) {
throw new HibernateException( "Unable to locate persister: " + entityName );
}
}
private IdentifierLoadAccessImpl(Class entityClass) {
this( entityClass.getName() );
}
@Override
public final IdentifierLoadAccessImpl<T> with(LockOptions lockOptions) {
public final IdentifierLoadAccessImpl with(LockOptions lockOptions) {
this.lockOptions = lockOptions;
return this;
}
/**
* Support for legacy {@link Session#load(Class, Serializable, LockMode)} and {@link Session#load(String, Serializable, LockMode)
* @deprecated
*/
@Deprecated
public final IdentifierLoadAccessImpl<T> with(LockMode lockMode) {
this.lockOptions = new LockOptions();
this.lockOptions.setLockMode( lockMode );
return this;
}
@Override
public final Object getReference(Serializable id) {
if ( this.lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityName, lockOptions, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this );
fireLoad( event, LoadEventListener.LOAD );
return event.getResult();
}
LoadEvent event = new LoadEvent( id, entityName, false, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this );
boolean success = false;
try {
fireLoad( event, LoadEventListener.LOAD );
if ( event.getResult() == null ) {
getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );
getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityPersister.getEntityName(), id );
}
success = true;
return event.getResult();
@ -2221,12 +2223,12 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
@Override
public final Object load(Serializable id) {
if ( this.lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityName, lockOptions, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this );
fireLoad( event, LoadEventListener.GET );
return event.getResult();
}
LoadEvent event = new LoadEvent( id, entityName, false, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this );
boolean success = false;
try {
fireLoad( event, LoadEventListener.GET );
@ -2239,39 +2241,47 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
}
}
private class NaturalIdLoadAccessImpl<T> implements NaturalIdLoadAccess<T> {
private final String entityName;
private final Class<T> entityClass;
private class NaturalIdLoadAccessImpl implements NaturalIdLoadAccess {
private final EntityPersister entityPersister;
private final Map<String, Object> naturalIdParameters = new LinkedHashMap<String, Object>();
private LockOptions lockOptions;
private NaturalIdLoadAccessImpl(String entityName, Class<T> entityClass) {
this.entityName = entityName;
this.entityClass = entityClass;
private NaturalIdLoadAccessImpl(EntityPersister entityPersister) {
this.entityPersister = entityPersister;
}
private NaturalIdLoadAccessImpl(String entityName) {
this( factory.getEntityPersister( entityName ) );
if ( entityPersister == null ) {
throw new HibernateException( "Unable to locate persister: " + entityName );
}
}
private NaturalIdLoadAccessImpl(Class entityClass) {
this( entityClass.getName() );
}
@Override
public final NaturalIdLoadAccess<T> with(LockOptions lockOptions) {
public final NaturalIdLoadAccess with(LockOptions lockOptions) {
this.lockOptions = lockOptions;
return this;
}
@Override
public NaturalIdLoadAccess<T> using(String attributeName, Object value) {
public NaturalIdLoadAccess using(String attributeName, Object value) {
naturalIdParameters.put( attributeName, value );
return this;
}
protected Serializable resolveNaturalId() {
final ResolveNaturalIdEvent event = new ResolveNaturalIdEvent( naturalIdParameters, entityName,
SessionImpl.this );
final ResolveNaturalIdEvent event =
new ResolveNaturalIdEvent( naturalIdParameters, entityPersister, SessionImpl.this );
fireResolveNaturalId( event );
return event.getEntityId();
}
protected IdentifierLoadAccess<T> getIdentifierLoadAccess() {
final IdentifierLoadAccessImpl<T> identifierLoadAccess = new SessionImpl.IdentifierLoadAccessImpl<T>(
entityName, entityClass );
protected IdentifierLoadAccess getIdentifierLoadAccess() {
final IdentifierLoadAccessImpl identifierLoadAccess = new IdentifierLoadAccessImpl( entityPersister );
if ( this.lockOptions != null ) {
identifierLoadAccess.with( lockOptions );
}

View File

@ -4504,29 +4504,59 @@ public abstract class AbstractEntityPersister
}
@Override
public Serializable loadEntityIdByNaturalId(Map<String, ?> naturalIdParameters, LockOptions lockOptions,
public Serializable loadEntityIdByNaturalId(
Map<String, ?> naturalIdValues,
LockOptions lockOptions,
SessionImplementor session) {
if ( !hasNaturalIdentifier() ) {
throw new MappingException( "persistent class did not define a natural-id : "
+ MessageHelper.infoString( this ) );
if ( ! entityMetamodel.hasNaturalIdentifier() ) {
throw new HibernateException(
String.format( "Entity [%s] does not define a natural-id", getEntityName() )
);
}
final int[] naturalIdPropertyIndexes = this.getNaturalIdentifierProperties();
if ( naturalIdPropertyIndexes.length != naturalIdValues.size() ) {
throw new HibernateException(
String.format(
"Entity [%s] defines its natural-id with %d properties but only %d were specified",
getEntityName(),
naturalIdPropertyIndexes.length,
naturalIdValues.size()
)
);
}
if ( LOG.isTraceEnabled() ) {
LOG.tracef(
"Resolving natural-id [%s] to id : %s ",
naturalIdValues,
MessageHelper.infoString( this )
);
}
if ( LOG.isTraceEnabled() )
LOG.trace( "Getting entity id for natural-id for: "
+ MessageHelper.infoString( this, naturalIdParameters, getFactory() ) );
try {
PreparedStatement ps = session.getTransactionCoordinator().getJdbcCoordinator().getStatementPreparer()
PreparedStatement ps = session.getTransactionCoordinator()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( sqlEntityIdByNaturalIdString );
try {
int positions = 1;
final int[] naturalIdPropertyIndexes = this.getNaturalIdentifierProperties();
for ( int propIdx = 0; propIdx < naturalIdPropertyIndexes.length; propIdx++ ) {
final int naturalIdIdx = naturalIdPropertyIndexes[propIdx];
for ( int naturalIdIdx : naturalIdPropertyIndexes ) {
final StandardProperty property = entityMetamodel.getProperties()[naturalIdIdx];
if ( ! naturalIdValues.containsKey( property.getName() ) ) {
throw new HibernateException(
String.format(
"No value specified for natural-id property %s#%s",
getEntityName(),
property.getName()
)
);
}
final Object value = naturalIdValues.get( property.getName() );
if ( value == null ) {
final StandardProperty[] properties = entityMetamodel.getProperties();
final StandardProperty property = properties[naturalIdIdx];
final Object value = naturalIdParameters.get( property.getName() );
}
final Type propertyType = property.getType();
propertyType.nullSafeSet( ps, value, positions, session );
@ -4553,9 +4583,13 @@ public abstract class AbstractEntityPersister
catch ( SQLException e ) {
throw getFactory().getSQLExceptionHelper().convert(
e,
"could not retrieve entity id: "
+ MessageHelper.infoString( this, naturalIdParameters, getFactory() ),
sqlEntityIdByNaturalIdString );
String.format(
"could not resolve natural-id [%s] to id : %s",
naturalIdValues,
MessageHelper.infoString( this )
),
sqlEntityIdByNaturalIdString
);
}
}
@ -4580,17 +4614,15 @@ public abstract class AbstractEntityPersister
final int naturalIdIdx = naturalIdPropertyIndexes[propIdx];
final String tableAlias = generateTableAlias( rootAlias, propertyTableNumbers[naturalIdIdx] );
final String[] propertyColumnNames = getPropertyColumnNames( naturalIdIdx );
final String[] aliasedPropertyColumns = StringHelper.qualify( rootAlias, propertyColumnNames );
final String[] aliasedPropertyColumns = StringHelper.qualify( tableAlias, propertyColumnNames );
whereClause.append( StringHelper.join( "=? and ", aliasedPropertyColumns ) ).append( "=?" );
}
whereClause.append( whereJoinFragment( getRootAlias(), true, false ) );
String sql = select.setOuterJoins( "", "" ).setWhereClause( whereClause.toString() ).toStatementString();
return sql;
return select.setOuterJoins( "", "" ).setWhereClause( whereClause.toString() ).toStatementString();
}
protected String concretePropertySelectFragmentSansLeadingComma(String alias, boolean[] include) {