many misc cleanups and doc for the Session hierarchy

This commit is contained in:
Gavin 2022-12-23 19:11:49 +01:00 committed by Gavin King
parent 974fe9e22d
commit fc62f33a55
15 changed files with 789 additions and 801 deletions

View File

@ -92,7 +92,7 @@ public final class Collections {
}
final EntityEntry e = persistenceContext.getEntry( owner );
//only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
if ( e != null && e.getStatus() != Status.DELETED && e.getStatus() != Status.GONE ) {
if ( e != null && !e.getStatus().isDeletedOrGone() ) {
throw new HibernateException(
"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: " +
loadedPersister.getRole()

View File

@ -27,7 +27,6 @@ import org.hibernate.MultiIdentifierLoadAccess;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.NaturalIdMultiLoadAccess;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.SessionEventListener;
import org.hibernate.SharedSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
@ -70,14 +69,13 @@ import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel;
/**
* This class is meant to be extended.
*
* Wraps and delegates all methods to a {@link SessionImplementor} and
* a {@link Session}. This is useful for custom implementations of this
* API so that only some methods need to be overridden
* A wrapper class that delegates all method invocations to a delegate instance of
* {@link SessionImplementor}. This is useful for custom implementations of that
* API, so that only some methods need to be overridden
* <p>
* (Used by Hibernate Search).
*
* @author <a href="mailto:sanne@hibernate.org">Sanne Grinovero</a> (C) 2012 Red Hat Inc.
* @author Sanne Grinovero
*/
@SuppressWarnings("deprecation")
public class SessionDelegatorBaseImpl implements SessionImplementor {
@ -89,8 +87,10 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
/**
* Returns the underlying delegate. Be careful that it has a different behavior from the {@link #getDelegate()}
* method coming from the EntityManager interface which returns the current session.
* Returns the delegate session.
* <p>
* @apiNote This returns a different object to the {@link #getDelegate()}
* method inherited from {@link jakarta.persistence.EntityManager}.
*
* @see SessionDelegatorBaseImpl#getDelegate()
*/
@ -650,11 +650,9 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
}
/**
* This is an implementation of EntityManager#getDelegate(). It returns the current session and not the delegate
* session as it is what we want. The name of the method is misleading here but, as it is part of JPA, we cannot do
* anything about it.
* <p>
* To get the underlying delegate, use {@link #delegate()} instead.
* This is the implementation of {@link jakarta.persistence.EntityManager#getDelegate()}.
* It returns this object and <em>not</em> what we call the "delegate" session here.
* To get the delegate session, use {@link #delegate()} instead.
*
* @see SessionDelegatorBaseImpl#delegate()
*/
@ -683,7 +681,6 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
return delegate.createStoredProcedureCall( procedureName, resultSetMappings );
}
@SuppressWarnings("rawtypes")
@Override
public SharedSessionBuilder sessionWithOptions() {
return delegate.sessionWithOptions();

View File

@ -9,43 +9,50 @@ package org.hibernate.engine.spi;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.MergeContext;
import org.hibernate.event.spi.PersistContext;
import org.hibernate.event.spi.RefreshContext;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.type.descriptor.WrapperOptions;
/**
* Defines the "internal contract" for {@link Session} and other parts of Hibernate such
* as {@link org.hibernate.type.Type}, {@link EntityPersister}
* and {@link org.hibernate.persister.collection.CollectionPersister} implementations.
*
* A Session, through this interface and SharedSessionContractImplementor, implements:
* Defines the "internal contract" between {@link Session} and other parts of Hibernate
* including implementors of {@link org.hibernate.type.Type}, {@link EntityPersister},
* and {@link org.hibernate.persister.collection.CollectionPersister}.
* <p>
* The {@code Session}, via this interface and {@link SharedSessionContractImplementor},
* implements:
* <ul>
* <li>
* {@link org.hibernate.resource.jdbc.spi.JdbcSessionOwner} to drive the behavior
* of the {@link org.hibernate.resource.jdbc.spi.JdbcSessionContext} delegate
* {@link JdbcSessionOwner}, and so the session also acts as the orchestrator
* of a "JDBC session", and may be used to construct a {@link JdbcCoordinator}.
* </li>
* <li>
* {@link TransactionCoordinatorBuilder.Options}
* to drive the creation of the {@link TransactionCoordinator} delegate
* {@link TransactionCoordinatorBuilder.Options}, allowing the session to control
* the creation of the {@link TransactionCoordinator} delegate when it is passed
* as an argument to
* {@link org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder#buildTransactionCoordinator}
* </li>
* <li>
* {@link org.hibernate.engine.jdbc.LobCreationContext} to act as the context for
* JDBC LOB instance creation
* {@link LobCreationContext}, and so the session may act as the context for
* JDBC LOB instance creation.
* </li>
* <li>
* {@link org.hibernate.type.descriptor.WrapperOptions} to fulfill the behavior
* needed while binding/extracting values to/from JDBC as part of the {@code Type}
* contracts
* {@link WrapperOptions}, and so the session may influence the process of binding
* and extracting values to and from JDBC, which is performed by implementors of
* {@link org.hibernate.type.descriptor.jdbc.JdbcType}.
* </li>
* </ul>
*
* See also {@link org.hibernate.event.spi.EventSource} which extends this interface
* providing s bridge to the event generation features of {@link org.hibernate.event}.
* provides a bridge to the event generation features of {@link org.hibernate.event}.
*
* @author Gavin King
* @author Steve Ebersole
@ -69,12 +76,21 @@ public interface SessionImplementor extends Session, SharedSessionContractImplem
@Override
RootGraphImplementor<?> getEntityGraph(String graphName);
/**
* Get the {@link ActionQueue} associated with this session.
*/
ActionQueue getActionQueue();
Object instantiate(EntityPersister persister, Object id) throws HibernateException;
/**
* Initiate a flush to force deletion of a re-persisted entity.
*/
void forceFlush(EntityEntry e) throws HibernateException;
/**
* Cascade the lock operation to the given child entity.
*/
void lock(String entityName, Object child, LockOptions lockOptions);
/**

View File

@ -16,7 +16,9 @@ import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.StatelessSession;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.event.spi.EventSource;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.query.Query;
import org.hibernate.SharedSessionContract;
import org.hibernate.Transaction;
@ -36,27 +38,30 @@ import org.hibernate.type.spi.TypeConfiguration;
/**
* Defines the internal contract shared between {@link org.hibernate.Session} and
* {@link org.hibernate.StatelessSession} as used by other parts of Hibernate (such as
* {@link org.hibernate.type.Type}, {@link EntityPersister} and
* {@link org.hibernate.persister.collection.CollectionPersister} implementors
*
* A Session, through this interface and SharedSessionContractImplementor, implements:<ul>
* {@link org.hibernate.StatelessSession} as used by other parts of Hibernate,
* including implementors of {@link org.hibernate.type.Type}, {@link EntityPersister},
* and {@link org.hibernate.persister.collection.CollectionPersister}.
* <p>
* The {@code Session}, via this interface and {@link SharedSessionContractImplementor},
* implements:
* <ul>
* <li>
* {@link JdbcSessionOwner} to drive the behavior of a "JDBC session".
* Can therefor be used to construct a JdbcCoordinator, which (for now) models a "JDBC session"
* {@link JdbcSessionOwner}, and so the session also acts as the orchestrator
* of a "JDBC session", and may be used to construct a {@link JdbcCoordinator}.
* </li>
* <li>
* {@link Options}
* to drive the creation of the {@link TransactionCoordinator} delegate.
* This allows it to be passed along to
* {@link Options}, allowing the session to control the creation of the
* {@link TransactionCoordinator} delegate when it is passed as an argument to
* {@link org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder#buildTransactionCoordinator}
* </li>
* <li>
* {@link LobCreationContext} to act as the context for JDBC LOB instance creation
* {@link LobCreationContext}, and so the session may act as the context for
* JDBC LOB instance creation.
* </li>
* <li>
* {@link WrapperOptions} to fulfill the behavior needed while
* binding/extracting values to/from JDBC as part of the Type contracts
* {@link WrapperOptions}, and so the session may influence the process of binding
* and extracting values to and from JDBC, which is performed by implementors of
* {@link org.hibernate.type.descriptor.jdbc.JdbcType}.
* </li>
* </ul>
*
@ -64,100 +69,117 @@ import org.hibernate.type.spi.TypeConfiguration;
* @author Steve Ebersole
*/
public interface SharedSessionContractImplementor
extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions, QueryProducerImplementor, JavaType.CoercionContext {
extends SharedSessionContract, JdbcSessionOwner, Options, LobCreationContext, WrapperOptions,
QueryProducerImplementor, JavaType.CoercionContext {
// todo : this is the shared contract between Session and StatelessSession, but it defines methods that StatelessSession does not implement
// (it just throws UnsupportedOperationException). To me it seems like it is better to properly isolate those methods
// into just the Session hierarchy. They include (at least):
// 1) get/set CacheMode
// 2) get/set FlushMode
// 3) get/set (default) read-only
// 4) #setAutoClear
// 5) #disableTransactionAutoJoin
// todo : this is the shared contract between Session and StatelessSession,
// but it defines methods that StatelessSession does not implement
// To me it seems like it is better to properly isolate those methods
// into just the Session hierarchy. They include (at least):
// 1) get/set CacheMode
// 2) get/set FlushMode
// 3) get/set (default) read-only
/**
* Get the creating {@code SessionFactoryImplementor}
* Obtain the {@linkplain SessionFactoryImplementor factory} which created this session.
*/
SessionFactoryImplementor getFactory();
/**
* Obtain the {@linkplain SessionFactoryImplementor factory} which created this session.
*/
@Override
default SessionFactoryImplementor getSessionFactory() {
return getFactory();
}
/**
* Obtain the {@link TypeConfiguration} for the factory which created this session.
*/
@Override
default TypeConfiguration getTypeConfiguration() {
return getFactory().getTypeConfiguration();
}
/**
* Get the {@link SessionEventListenerManager} associated with this session.
*/
SessionEventListenerManager getEventListenerManager();
/**
* Get the persistence context for this session.
* See also {@link #getPersistenceContextInternal()} for
* an alternative.
* <p>
* See {@link #getPersistenceContextInternal()} for
* a faster alternative.
*
* This method is not extremely fast: if you need to access
* the PersistenceContext multiple times, prefer keeping
* a reference to it over invoking this method multiple times.
* @implNote This method is not extremely fast: if you need to
* call the {@link PersistenceContext} multiple times,
* prefer keeping a reference to it instead of invoking
* this method multiple times.
*/
PersistenceContext getPersistenceContext();
/**
* Obtain the {@link JdbcCoordinator} for this session.
*/
JdbcCoordinator getJdbcCoordinator();
/**
* Obtain the {@link JdbcServices} for the factory which created this session.
*/
JdbcServices getJdbcServices();
/**
* The multi-tenancy tenant identifier, if one.
*
* @return The tenant identifier; may be {@code null}
*/
String getTenantIdentifier();
/**
* A UUID associated with each Session. Useful mainly for logging.
*
* @return The UUID
* Obtain a {@link UUID} which uniquely identifies this session.
* <p>
* The UUID is useful mainly for logging.
*/
UUID getSessionIdentifier();
/**
* Returns this object, fulfilling the contract of {@link WrapperOptions}.
*/
@Override
default SharedSessionContractImplementor getSession() {
return this;
}
/**
* A "token" that is unique to this Session.
*
* @return The token
* Obtain a "token" which uniquely identifies this session.
*/
default Object getSessionToken() {
return this;
}
/**
* Checks whether the session is closed. Provided separately from
* {@link #isOpen()} as this method does not attempt any JTA synchronization
* registration, whereas {@link #isOpen()} does; which makes this one
* nicer to use for most internal purposes.
* Determines whether the session is closed.
* <p>
* @apiNote Provided separately from {@link #isOpen()} as this method
* does not attempt any JTA synchronization registration,
* whereas {@link #isOpen()} does. This one is better for most
* internal purposes.
*
* @return {@code true} if the session is closed; {@code false} otherwise.
*/
boolean isClosed();
/**
* Checks whether the session is open or is waiting for auto-close
* Determines whether the session is open or is waiting for auto-close.
*
* @return {@code true} if the session is closed or if it's waiting for auto-close; {@code false} otherwise.
* @return {@code true} if the session is closed, or if it's waiting
* for auto-close; {@code false} otherwise.
*/
default boolean isOpenOrWaitingForAutoClose() {
return !isClosed();
}
/**
* Performs a check whether the Session is open, and if not:<ul>
* <li>marks current transaction (if one) for rollback only</li>
* <li>throws an IllegalStateException (JPA defines the exception type)</li>
* Check whether the session is open, and if not:
* <ul>
* <li>mark the current transaction, if any, for rollback only,
* and</li>
* <li>throw an {@code IllegalStateException}.
* (JPA specifies this exception type.)</li>
* </ul>
*/
default void checkOpen() {
@ -165,9 +187,12 @@ public interface SharedSessionContractImplementor
}
/**
* Performs a check whether the Session is open, and if not:<ul>
* <li>if {@code markForRollbackIfClosed} is true, marks current transaction (if one) for rollback only</li>
* <li>throws an IllegalStateException (JPA defines the exception type)</li>
* Check whether the session is open, and if not:
* <ul>
* <li>if {@code markForRollbackIfClosed = true}, mark the
* current transaction, if any, for rollback only, and
* <li>throw an {@code IllegalStateException}.
* (JPA specifies this exception type.)
* </ul>
*/
void checkOpen(boolean markForRollbackIfClosed);
@ -179,27 +204,31 @@ public interface SharedSessionContractImplementor
void prepareForQueryExecution(boolean requiresTxn);
/**
* Marks current transaction (if one) for rollback only
* Marks current transaction, if any, for rollback only.
*/
void markForRollbackOnly();
/**
* The current CacheTransactionContext associated with the Session. This may
* return {@code null} when the Session is not currently part of a transaction.
* The current {@link CacheTransactionSynchronization} associated
* with this session. This may be {@code null} if the session is not
* currently associated with an active transaction.
*/
CacheTransactionSynchronization getCacheTransactionSynchronization();
/**
* Does this {@code Session} have an active Hibernate transaction
* or is there a JTA transaction in progress?
* Does this session have an active Hibernate transaction, or is it
* associated with a JTA transaction currently in progress?
*/
boolean isTransactionInProgress();
/**
* Check if an active Transaction is necessary for the update operation to be executed.
* If an active Transaction is necessary but it is not then a TransactionRequiredException is raised.
* Check if an active {@link Transaction} is available before performing
* an update operation against the database.
* <p>
* If an active transaction is necessary, but no transaction is active,
* a {@link TransactionRequiredException} is raised.
*
* @param exceptionMessage the message to use for the TransactionRequiredException
* @param exceptionMessage the message to use for the {@link TransactionRequiredException}
*/
default void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
if ( !isTransactionInProgress() ) {
@ -208,16 +237,18 @@ public interface SharedSessionContractImplementor
}
/**
* Provides access to the underlying transaction or creates a new transaction if
* one does not already exist or is active. This is primarily for internal or
* integrator use.
* Retrieves the current {@link Transaction}, or creates a new transaction
* if there is no transaction active.
* <p>
* This method is primarily for internal or integrator use.
*
* @return the transaction
* @return the {@link Transaction}
*/
Transaction accessTransaction();
/**
* Hide the changing requirements of entity key creation
* Instantiate an {@link EntityKey} with the given id and for the
* entity represented by the given {@link EntityPersister}.
*
* @param id The entity id
* @param persister The entity persister
@ -227,48 +258,50 @@ public interface SharedSessionContractImplementor
EntityKey generateEntityKey(Object id, EntityPersister persister);
/**
* Retrieves the interceptor currently in use by this event source.
*
* @return The interceptor.
* Retrieves the {@link Interceptor} associated with this session.
*/
Interceptor getInterceptor();
/**
* Enable/disable automatic cache clearing from after transaction
* completion (for EJB3)
* Enable or disable automatic cache clearing from after transaction
* completion.
*
* @deprecated there's no good reason to expose this here
*/
@Deprecated(since = "6")
void setAutoClear(boolean enabled);
/**
* Initialize the collection (if not already initialized)
* Initialize the given collection (if not already initialized).
*/
void initializeCollection(PersistentCollection<?> collection, boolean writing)
throws HibernateException;
/**
* Load an instance without checking if it was deleted.
* <p>
* When {@code nullable} is disabled this method may create a new proxy or
* return an existing proxy; if it does not exist, throw an exception.
* <p>
* When {@code nullable} is enabled, the method does not create new proxies
* (but might return an existing proxy); if it does not exist, return
* {@code null}.
* <p>
* When {@code eager} is enabled, the object is eagerly fetched
* Obtain an entity instance with the given id, without checking if it was
* deleted or scheduled for deletion.
* <ul>
* <li>When {@code nullable = false}, this method may create a new proxy or
* return an existing proxy; if it does not exist, an exception is thrown.
* <li>When {@code nullable = true}, the method does not create new proxies,
* though it might return an existing proxy; if it does not exist, a
* {@code null} value is returned.
* </ul>
* When {@code eager = true}, the object is eagerly fetched from the database.
*/
Object internalLoad(String entityName, Object id, boolean eager, boolean nullable)
throws HibernateException;
/**
* Load an instance immediately. This method is only called when lazily initializing a proxy.
* Load an instance immediately.
* This method is only called when lazily initializing a proxy.
* Do not return the proxy.
*/
Object immediateLoad(String entityName, Object id) throws HibernateException;
/**
* Get the {@code EntityPersister} for any instance
* Get the {@link EntityPersister} for the given entity instance.
*
* @param entityName optional entity name
* @param object the entity instance
@ -276,43 +309,60 @@ public interface SharedSessionContractImplementor
EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException;
/**
* Get the entity instance associated with the given {@code Key},
* calling the Interceptor if necessary
* Get the entity instance associated with the given {@link EntityKey},
* calling the {@link Interceptor} if necessary.
*/
Object getEntityUsingInterceptor(EntityKey key) throws HibernateException;
/**
* Return the identifier of the persistent object, or null if
* not associated with the session
* Return the identifier of the persistent object, or null if it is
* not associated with this session.
*/
Object getContextEntityIdentifier(Object object);
/**
* The best guess entity name for an entity not in an association
* Obtain the best estimate of the entity name of the given entity
* instance, which is not involved in an association, by also
* considering information held in the proxy, and whether the object
* is already associated with this session.
*/
String bestGuessEntityName(Object object);
/**
* The guessed entity name for an entity not in an association
* Obtain an estimate of the entity name of the given entity instance,
* which is not involved in an association, using only the
* {@link org.hibernate.EntityNameResolver}.
*/
String guessEntityName(Object entity) throws HibernateException;
/**
* Instantiate the entity class, initializing with the given identifier
* Instantiate the entity class, initializing with the given identifier.
*/
Object instantiate(String entityName, Object id) throws HibernateException;
/**
* Instantiate the entity class of an EntityPersister, initializing with the given identifier.
* This is more efficient than {@link #instantiate(String, Object)} but not always
* interchangeable: a single persister might be responsible for multiple types.
* Instantiate the entity class of the given {@link EntityPersister},
* initializing the new instance with the given identifier.
* <p>
* This is more efficient than {@link #instantiate(String, Object)},
* but not always interchangeable, since a single persister might be
* responsible for multiple types.
*/
Object instantiate(EntityPersister persister, Object id) throws HibernateException;
/**
* Are entities and proxies loaded by this session read-only by default?
*/
boolean isDefaultReadOnly();
/**
* Get the current {@link CacheMode} for this session.
*/
CacheMode getCacheMode();
/**
* Set the current {@link CacheMode} for this session.
*/
void setCacheMode(CacheMode cm);
void setCriteriaCopyTreeEnabled(boolean jpaCriteriaCopyComplianceEnabled);
@ -320,73 +370,121 @@ public interface SharedSessionContractImplementor
boolean isCriteriaCopyTreeEnabled();
/**
* Get the flush mode for this session.
* Get the current {@link FlushModeType} for this session.
* <p>
* For users of the Hibernate native APIs, we've had to rename this method
* as defined by Hibernate historically because the JPA contract defines a method of the same
* name, but returning the JPA {@link FlushModeType} rather than Hibernate's {@link FlushMode}. For
* the former behavior, use {@link #getHibernateFlushMode()} instead.
* name, but returning the JPA {@link FlushModeType} rather than Hibernate's {@link FlushMode}.
* For the former behavior, use {@link #getHibernateFlushMode()} instead.
*
* @return The FlushModeType in effect for this Session.
* @return The {@link FlushModeType} in effect for this Session.
*
* @deprecated there's no good reason to expose this here
*/
@Deprecated(since = "6")
FlushModeType getFlushMode();
/**
* Set the flush mode for this session.
* Set the current {@link FlushMode} for this session.
* <p>
* The flush mode determines the points at which the session is flushed.
* <i>Flushing</i> is the process of synchronizing the underlying persistent
* store with persistable state held in memory.
* <p>
* For a logically "read only" session, it is reasonable to set the session's
* flush mode to {@link FlushMode#MANUAL} at the start of the session (in
* order to achieve some extra performance).
* For a logically "read-only" session, it's reasonable to set the session
* flush mode to {@link FlushMode#MANUAL} at the start of the session
* (in order skip some work and gain some extra performance).
*
* @param flushMode the new flush mode
*/
void setHibernateFlushMode(FlushMode flushMode);
/**
* Get the current flush mode for this session.
* Get the current {@link FlushMode} for this session.
*
* @return The flush mode
*/
FlushMode getHibernateFlushMode();
/**
* Flush this session.
*/
void flush();
boolean isEventSource();
/**
* Determines if this session implements {@link EventSource}.
* <p>
* Only stateful session are sources of events. If this object is
* a stateless session, this method return {@code false}.
*/
default boolean isEventSource() {
return false;
}
EventSource asEventSource();
/**
* Cast this session to {@link EventSource} if possible.
* <p>
* Only stateful session are sources of events. If this object is
* a stateless session, this method throws.
*
* @throws ClassCastException if the cast is not possible
*/
default EventSource asEventSource() {
throw new ClassCastException( "session is not an EventSource" );
}
/**
* Called after each operation on a {@link org.hibernate.ScrollableResults},
* providing an opportunity for a stateless session to clear its
* temporary persistence context. For a stateful session, this method
* does nothing.
*/
void afterScrollOperation();
/**
* Should this session be automatically closed after the current
* transaction completes?
*
* @deprecated there's no reason to expose this here
*/
@Deprecated(since = "6")
boolean shouldAutoClose();
/**
* Is auto-close at transaction completion enabled?
*
* @see org.hibernate.cfg.AvailableSettings#AUTO_CLOSE_SESSION
* @see SessionFactoryOptions#isAutoCloseSessionEnabled()
*
* @deprecated there's no reason to expose this here
*/
@Deprecated(since = "6")
boolean isAutoCloseSessionEnabled();
/**
* Get the load query influencers associated with this session.
* Get the {@link LoadQueryInfluencers} associated with this session.
*
* @return the load query influencers associated with this session;
* @return the {@link LoadQueryInfluencers} associated with this session;
* should never be null.
*/
LoadQueryInfluencers getLoadQueryInfluencers();
/**
* The converter associated to a Session might be lazily initialized: only invoke
* this getter when there is actual need to use it.
* Obtain an {@link ExceptionConverter} for reporting an error.
* <p>
* The converter associated to a session might be lazily initialized,
* so only invoke this getter when there's an actual need to use it.
*
* @return the ExceptionConverter for this Session.
*/
ExceptionConverter getExceptionConverter();
/**
* Get the currently configured JDBC batch size either at the Session-level or SessionFactory-level.
* Get the currently configured JDBC batch size, which might have
* been specified at either the session or factory level.
*
* If the Session-level JDBC batch size was not configured, return the SessionFactory-level one.
*
* @return Session-level or SessionFactory-level JDBC batch size.
* @return the session-level JDBC batch size is set, or the
* factory-level setting otherwise
*
* @since 5.2
*
@ -401,16 +499,15 @@ public interface SharedSessionContractImplementor
}
/**
* This is similar to {@link #getPersistenceContext()}, with
* two main differences:
* a) this version performs better as
* it allows for inlining and probably better prediction
* b) see SessionImpl{@link #getPersistenceContext()} : it
* does some checks on the current state of the Session.
* Similar to {@link #getPersistenceContext()}, with two differences:
* <ol>
* <li>this version performs better as it allows for inlining
* and probably better prediction, and
* <li>it skips some checks of the current state of the session.
* </ol>
* Choose wisely: performance is important, but correctness comes first.
*
* Choose wisely: performance is important, correctness comes first.
*
* @return the PersistenceContext associated to this session.
* @return the {@link PersistenceContext} associated to this session.
*/
PersistenceContext getPersistenceContextInternal();
@ -424,45 +521,63 @@ public interface SharedSessionContractImplementor
*/
boolean autoFlushIfRequired(Set<String> querySpaces) throws HibernateException;
/**
* Are we currently enforcing a {@linkplain GraphSemantic#FETCH fetch graph}?
*
* @deprecated this is not used anywhere
*/
@Deprecated(since = "6", forRemoval = true)
default boolean isEnforcingFetchGraph() {
return false;
}
/**
* Enable or disable {@linkplain GraphSemantic#FETCH fetch graph} enforcement.
*
* @deprecated this is not used anywhere
*/
@Deprecated(since = "6", forRemoval = true)
default void setEnforcingFetchGraph(boolean enforcingFetchGraph) {
}
/**
* Check if there is a Hibernate or JTA transaction in progress and,
* 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
* if there is not, flush if necessary, making sure that the connection
* has been committed (if it is not in autocommit mode), and finally
* run the after completion processing.
*
* @param success Was the operation a success
* @param success {@code true} if the operation a success
*/
void afterOperation(boolean success);
/**
* If this can be casted to a @{@link SessionImplementor},
* you'll get this returned after an efficient cast.
* @throws ClassCastException if this is not compatible!
* Cast this object to {@link SessionImplementor}, if possible.
*
* @throws ClassCastException if the cast is not possible
*/
default SessionImplementor asSessionImplementor() {
throw new ClassCastException();
throw new ClassCastException( "session is not a SessionImplementor" );
}
/**
* Does this object implement {@link SessionImplementor}?
*/
default boolean isSessionImplementor() {
return false;
}
/**
* If this can be casted to a @{@link StatelessSession},
* you'll get this returned after an efficient cast.
* @throws ClassCastException if this is not compatible!
* Cast this object to {@link StatelessSession}, if possible.
*
* @throws ClassCastException if the cast is not possible
*/
default StatelessSession asStatelessSession() {
throw new ClassCastException();
throw new ClassCastException( "session is not a StatelessSession" );
}
/**
* Does this object implement {@link StatelessSession}?
*/
default boolean isStatelessSession() {
return false;
}

View File

@ -18,5 +18,9 @@ public enum Status {
DELETED,
GONE,
LOADING,
SAVING
SAVING;
public boolean isDeletedOrGone() {
return this == DELETED || this == GONE;
}
}

View File

@ -210,7 +210,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
EntityEntry entityEntry) {
LOG.trace( "Deleting a persistent instance" );
final EventSource source = event.getSession();
if ( entityEntry.getStatus() == Status.DELETED || entityEntry.getStatus() == Status.GONE
if ( entityEntry.getStatus().isDeletedOrGone()
|| source.getPersistenceContextInternal()
.containsDeletedUnloadedEntityKey( entityEntry.getEntityKey() ) ) {
LOG.trace( "Object was already deleted" );

View File

@ -443,8 +443,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
}
private static boolean wasDeleted(PersistenceContext persistenceContext, Object existing) {
final Status status = persistenceContext.getEntry( existing ).getStatus();
return status == Status.DELETED || status == Status.GONE;
return persistenceContext.getEntry( existing ).getStatus().isDeletedOrGone();
}
private static Object createProxy(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) {

View File

@ -17,7 +17,6 @@ import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -29,7 +28,6 @@ import org.hibernate.FetchNotFoundException;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.IdentifierLoadAccess;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.LobHelper;
@ -53,7 +51,6 @@ import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.binder.internal.TenantIdBinder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.internal.StatefulPersistenceContext;
@ -113,7 +110,6 @@ import org.hibernate.graph.internal.RootGraphImpl;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jpa.internal.LegacySpecHelper;
import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
@ -126,7 +122,6 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.Query;
import org.hibernate.query.SelectionQuery;
@ -154,21 +149,17 @@ import jakarta.persistence.PersistenceException;
import jakarta.persistence.TransactionRequiredException;
import jakarta.persistence.metamodel.Metamodel;
import static java.lang.Boolean.parseBoolean;
import static java.util.Collections.unmodifiableMap;
import static org.hibernate.CacheMode.fromJpaModes;
import static org.hibernate.cfg.AvailableSettings.CRITERIA_COPY_TREE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.cfg.AvailableSettings.*;
import static org.hibernate.jpa.HibernateHints.HINT_READ_ONLY;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_LOCK_TIMEOUT;
import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_LOCK_TIMEOUT;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_QUERY_TIMEOUT;
import static org.hibernate.jpa.internal.util.CacheModeHelper.interpretCacheMode;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* Concrete implementation of the {@link Session} API.
@ -210,6 +201,7 @@ public class SessionImpl
private transient TransactionObserver transactionObserver;
// TODO: this is unused and can be removed
private transient boolean isEnforcingFetchGraph;
public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
@ -254,7 +246,7 @@ public class SessionImpl
final FlushMode initialMode = this.properties == null
? fastSessionServices.initialSessionFlushMode
: ConfigurationHelper.getFlushMode(
getSessionProperty(AvailableSettings.FLUSH_MODE),
getSessionProperty(FLUSH_MODE),
FlushMode.AUTO
);
setHibernateFlushMode( initialMode );
@ -269,7 +261,7 @@ public class SessionImpl
CurrentTenantIdentifierResolver resolver = factory.getCurrentTenantIdentifierResolver();
if ( resolver==null || !resolver.isRoot(tenantIdentifier) ) {
// turn on the filter, unless this is the "root" tenant with access to all partitions
getLoadQueryInfluencers()
loadQueryInfluencers
.enableFilter( TenantIdBinder.FILTER_NAME )
.setParameter( TenantIdBinder.PARAMETER_NAME, tenantIdentifier );
}
@ -536,7 +528,7 @@ public class SessionImpl
throw new NullPointerException( "null object passed to getCurrentLockMode()" );
}
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
object = lazyInitializer.getImplementation( this );
if ( object == null ) {
@ -1037,7 +1029,7 @@ public class SessionImpl
fireLoadNoChecks( event, LoadEventListener.IMMEDIATE_LOAD );
Object result = event.getResult();
finishWithEventInstance( event );
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( result );
final LazyInitializer lazyInitializer = extractLazyInitializer( result );
if ( lazyInitializer != null ) {
return lazyInitializer.getImplementation();
}
@ -1051,7 +1043,7 @@ public class SessionImpl
boolean eager,
boolean nullable) {
final LoadType type = internalLoadType( eager, nullable );
final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph();
final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph();
final GraphSemantic semantic = effectiveEntityGraph.getSemantic();
final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph();
boolean clearedEffectiveGraph = false;
@ -1484,11 +1476,11 @@ public class SessionImpl
.getEntityDescriptor( entityName )
.getSubclassEntityPersister( object, getFactory() );
}
catch (HibernateException e) {
catch ( HibernateException e ) {
try {
return getEntityPersister( null, object );
}
catch (HibernateException e2) {
catch ( HibernateException e2 ) {
throw e;
}
}
@ -1500,7 +1492,7 @@ public class SessionImpl
public Object getIdentifier(Object object) throws HibernateException {
checkOpen();
checkTransactionSynchStatus();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
if ( lazyInitializer.getSession() != this ) {
throw new TransientObjectException( "The proxy was not associated with this session" );
@ -1508,7 +1500,7 @@ public class SessionImpl
return lazyInitializer.getInternalIdentifier();
}
else {
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
if ( entry == null ) {
throw new TransientObjectException( "The instance was not associated with this session" );
}
@ -1523,12 +1515,12 @@ public class SessionImpl
@Override
public Object getContextEntityIdentifier(Object object) {
checkOpenOrWaitingForAutoClose();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
return lazyInitializer.getInternalIdentifier();
}
else {
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
return entry != null ? entry.getId() : null;
}
}
@ -1543,7 +1535,7 @@ public class SessionImpl
}
try {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
//do not use proxiesByKey, since not all
//proxies that point to this session's
@ -1570,7 +1562,7 @@ public class SessionImpl
delayedAfterCompletion();
if ( entry == null ) {
if ( ! ( lazyInitializer != null ) && persistenceContext.getEntry( object ) == null ) {
if ( lazyInitializer == null && persistenceContext.getEntry( object ) == null ) {
// check if it is even an entity -> if not throw an exception (per JPA)
try {
final String entityName = getEntityNameResolver().resolveEntityName( object );
@ -1581,20 +1573,20 @@ public class SessionImpl
.getMappingMetamodel()
.getEntityDescriptor( entityName );
}
catch (HibernateException e) {
catch ( HibernateException e ) {
throw new IllegalArgumentException( "Not an entity [" + object.getClass() + "]", e );
}
}
return false;
}
else {
return entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE;
return !entry.getStatus().isDeletedOrGone();
}
}
catch (MappingException e) {
catch ( MappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
catch (RuntimeException e) {
catch ( RuntimeException e ) {
throw getExceptionConverter().convert( e );
}
}
@ -1609,7 +1601,7 @@ public class SessionImpl
}
try {
final LazyInitializer li = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer li = extractLazyInitializer( object );
if ( ! ( li != null ) && persistenceContext.getEntry( object ) == null ) {
// check if it is an entity -> if not throw an exception (per JPA)
try {
@ -1643,14 +1635,14 @@ public class SessionImpl
// A session is considered to contain an entity only if the entity has
// an entry in the session's persistence context and the entry reports
// that the entity has not been removed
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
delayedAfterCompletion();
return entry != null && entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE;
return entry != null && !entry.getStatus().isDeletedOrGone();
}
catch (MappingException e) {
catch ( MappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
catch (RuntimeException e) {
catch ( RuntimeException e ) {
throw getExceptionConverter().convert( e );
}
}
@ -1694,7 +1686,7 @@ public class SessionImpl
@Override
public String bestGuessEntityName(Object object) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
// it is possible for this method to be called during flush processing,
// so make certain that we do not accidentally initialize an uninitialized proxy
@ -1703,7 +1695,7 @@ public class SessionImpl
}
object = lazyInitializer.getImplementation();
}
EntityEntry entry = persistenceContext.getEntry( object );
final EntityEntry entry = persistenceContext.getEntry( object );
if ( entry == null ) {
return guessEntityName( object );
}
@ -1716,7 +1708,7 @@ public class SessionImpl
public String getEntityName(Object object) {
checkOpen();
// checkTransactionSynchStatus();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
if ( !persistenceContext.containsProxy( object ) ) {
throw new TransientObjectException( "proxy was not associated with the session" );
@ -1734,7 +1726,7 @@ public class SessionImpl
@Override @SuppressWarnings("unchecked")
public <T> T getReference(T object) {
checkOpen();
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
return (T) getReference( lazyInitializer.getPersistentClass(), lazyInitializer.getIdentifier() );
}
@ -1765,22 +1757,22 @@ public class SessionImpl
@Override
public String toString() {
StringBuilder buf = new StringBuilder( 500 )
final StringBuilder string = new StringBuilder( 500 )
.append( "SessionImpl(" ).append( System.identityHashCode( this ) );
if ( !isClosed() ) {
if ( log.isTraceEnabled() ) {
buf.append( persistenceContext )
string.append( persistenceContext )
.append( ";" )
.append( actionQueue );
}
else {
buf.append( "<open>" );
string.append( "<open>" );
}
}
else {
buf.append( "<closed>" );
string.append( "<closed>" );
}
return buf.append( ')' ).toString();
return string.append( ')' ).toString();
}
@Override
@ -2205,7 +2197,7 @@ public class SessionImpl
@Override
protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) {
this.transactionObserver = new TransactionObserver() {
transactionObserver = new TransactionObserver() {
@Override
public void afterBegin() {
}
@ -2219,7 +2211,7 @@ public class SessionImpl
try {
getInterceptor().beforeTransactionCompletion( getTransactionIfAccessible() );
}
catch (Throwable t) {
catch ( Throwable t ) {
log.exceptionInBeforeTransactionCompletionInterceptor( t );
}
}
@ -2232,7 +2224,7 @@ public class SessionImpl
}
}
};
transactionCoordinator.addObserver(transactionObserver);
transactionCoordinator.addObserver( transactionObserver );
}
@Override
@ -2267,17 +2259,19 @@ public class SessionImpl
@Override
public void flushBeforeTransactionCompletion() {
final boolean doFlush = isTransactionFlushable()
&& getHibernateFlushMode() != FlushMode.MANUAL;
try {
if ( doFlush ) {
if ( mustFlushBeforeCompletion() ) {
try {
managedFlush();
}
catch ( RuntimeException re ) {
throw ExceptionMapperStandardImpl.INSTANCE
.mapManagedFlushFailure( "error during managed flush", re, this );
}
}
catch (RuntimeException re) {
throw ExceptionMapperStandardImpl.INSTANCE.mapManagedFlushFailure( "error during managed flush", re, this );
}
}
private boolean mustFlushBeforeCompletion() {
return isTransactionFlushable() && getHibernateFlushMode() != FlushMode.MANUAL;
}
private boolean isTransactionFlushable() {
@ -2285,8 +2279,10 @@ public class SessionImpl
// assume it is flushable - CMT, auto-commit, etc
return true;
}
final TransactionStatus status = getCurrentTransaction().getStatus();
return status == TransactionStatus.ACTIVE || status == TransactionStatus.COMMITTING;
else {
final TransactionStatus status = getCurrentTransaction().getStatus();
return status == TransactionStatus.ACTIVE || status == TransactionStatus.COMMITTING;
}
}
@Override
@ -2354,35 +2350,31 @@ public class SessionImpl
checkOpen();
LockOptions lockOptions = null;
try {
getLoadQueryInfluencers().getEffectiveEntityGraph().applyConfiguredGraph( properties );
Boolean readOnly = properties == null ? null : (Boolean) properties.get( HINT_READ_ONLY );
getLoadQueryInfluencers().setReadOnly( readOnly );
final IdentifierLoadAccess<T> loadAccess = byId( entityClass );
loadAccess.with( determineAppropriateLocalCacheMode( properties ) );
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeededForUpdateOperation();
}
checkTransactionNeededForLock( lockModeType );
lockOptions = buildLockOptions( lockModeType, properties );
loadAccess.with( lockOptions );
}
if ( getLoadQueryInfluencers().getEffectiveEntityGraph().getSemantic() == GraphSemantic.FETCH ) {
final EffectiveEntityGraph effectiveEntityGraph = loadQueryInfluencers.getEffectiveEntityGraph();
effectiveEntityGraph.applyConfiguredGraph( properties );
loadQueryInfluencers.setReadOnly( getReadOnlyHint( properties ) );
if ( effectiveEntityGraph.getSemantic() == GraphSemantic.FETCH ) {
setEnforcingFetchGraph( true );
}
return loadAccess.load( primaryKey );
return byId( entityClass )
.with( determineAppropriateLocalCacheMode( properties ) )
.with( lockOptions )
.load( primaryKey );
}
catch (EntityNotFoundException entityNotFoundException) {
catch ( EntityNotFoundException enfe ) {
/*
This may happen if the entity has an associations mapped with @NotFound(action = NotFoundAction.EXCEPTION)
and this associated entity is not found.
*/
if ( entityNotFoundException instanceof FetchNotFoundException ) {
throw entityNotFoundException;
if ( enfe instanceof FetchNotFoundException ) {
throw enfe;
}
// DefaultLoadEventListener#returnNarrowedProxy() may throw ENFE (see HHH-7861 for details),
// which find() should not throw. Find() should return null if the entity was not found.
@ -2423,12 +2415,22 @@ public class SessionImpl
throw getExceptionConverter().convert( e, lockOptions );
}
finally {
getLoadQueryInfluencers().getEffectiveEntityGraph().clear();
getLoadQueryInfluencers().setReadOnly( null );
loadQueryInfluencers.getEffectiveEntityGraph().clear();
loadQueryInfluencers.setReadOnly( null );
setEnforcingFetchGraph( false );
}
}
private void checkTransactionNeededForLock(LockModeType lockModeType) {
if ( lockModeType != LockModeType.NONE ) {
checkTransactionNeededForUpdateOperation();
}
}
private static Boolean getReadOnlyHint(Map<String, Object> properties) {
return properties == null ? null : (Boolean) properties.get( HINT_READ_ONLY );
}
protected CacheMode determineAppropriateLocalCacheMode(Map<String, Object> localProperties) {
CacheRetrieveMode retrieveMode = null;
CacheStoreMode storeMode = null;
@ -2444,23 +2446,21 @@ public class SessionImpl
// use the EM setting
storeMode = fastSessionServices.getCacheStoreMode( this.properties );
}
return CacheModeHelper.interpretCacheMode( storeMode, retrieveMode );
return interpretCacheMode( storeMode, retrieveMode );
}
private static CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE );
if ( cacheRetrieveMode == null ) {
return (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE );
}
return cacheRetrieveMode;
return cacheRetrieveMode == null
? (CacheRetrieveMode) settings.get( JAKARTA_SHARED_CACHE_RETRIEVE_MODE )
: cacheRetrieveMode;
}
private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE );
if ( cacheStoreMode == null ) {
return ( CacheStoreMode ) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE );
}
return cacheStoreMode;
return cacheStoreMode == null
? (CacheStoreMode) settings.get( JAKARTA_SHARED_CACHE_STORE_MODE )
: cacheStoreMode;
}
private void checkTransactionNeededForUpdateOperation() {
@ -2546,10 +2546,7 @@ public class SessionImpl
}
if ( lockModeType != null ) {
if ( !LockModeType.NONE.equals( lockModeType) ) {
checkTransactionNeededForUpdateOperation();
}
checkTransactionNeededForLock( lockModeType );
lockOptions = buildLockOptions( lockModeType, properties );
refresh( entity, lockOptions );
}
@ -2557,10 +2554,10 @@ public class SessionImpl
refresh( entity );
}
}
catch (MappingException e) {
catch ( MappingException e ) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage(), e ) );
}
catch (RuntimeException e) {
catch ( RuntimeException e ) {
throw getExceptionConverter().convert( e, lockOptions );
}
finally {
@ -2612,46 +2609,48 @@ public class SessionImpl
checkOpen();
if ( !( value instanceof Serializable ) ) {
log.warnf( "Property '%s' is not serializable, value won't be set.", propertyName );
log.warnf( "Property '%s' is not serializable, value won't be set", propertyName );
return;
}
if ( propertyName == null ) {
log.warn( "Property having key null is illegal; value won't be set." );
log.warn( "Property having key null is illegal, value won't be set" );
return;
}
//Store property for future reference:
// store property for future reference:
if ( properties == null ) {
properties = computeCurrentSessionProperties();
}
properties.put( propertyName, value );
//now actually update settings, if it's any of these which have a direct impact on this Session state:
// now actually update the setting, if it's one which affects this Session
interpretProperty( propertyName, value );
}
switch (propertyName) {
case AvailableSettings.FLUSH_MODE:
private void interpretProperty(String propertyName, Object value) {
switch ( propertyName ) {
case FLUSH_MODE:
setHibernateFlushMode( ConfigurationHelper.getFlushMode(value, FlushMode.AUTO) );
break;
case JPA_LOCK_SCOPE:
case JAKARTA_LOCK_SCOPE:
properties.put( JPA_LOCK_SCOPE, value );
properties.put( JAKARTA_LOCK_SCOPE, value );
LockOptionsHelper.applyPropertiesToLockOptions(properties, this::getLockOptionsForWrite);
properties.put( JPA_LOCK_SCOPE, value);
properties.put( JAKARTA_LOCK_SCOPE, value);
LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite );
break;
case JPA_LOCK_TIMEOUT:
case JAKARTA_LOCK_TIMEOUT:
properties.put( JPA_LOCK_TIMEOUT, value );
properties.put( JAKARTA_LOCK_TIMEOUT, value );
LockOptionsHelper.applyPropertiesToLockOptions(properties, this::getLockOptionsForWrite);
LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite );
break;
case JPA_SHARED_CACHE_RETRIEVE_MODE:
case JAKARTA_SHARED_CACHE_RETRIEVE_MODE:
properties.put( JPA_SHARED_CACHE_RETRIEVE_MODE, value );
properties.put( JAKARTA_SHARED_CACHE_RETRIEVE_MODE, value );
setCacheMode(
CacheModeHelper.interpretCacheMode(
interpretCacheMode(
determineCacheStoreMode( properties ),
(CacheRetrieveMode) value
)
@ -2662,23 +2661,23 @@ public class SessionImpl
properties.put( JPA_SHARED_CACHE_STORE_MODE, value );
properties.put( JAKARTA_SHARED_CACHE_STORE_MODE, value );
setCacheMode(
CacheModeHelper.interpretCacheMode(
interpretCacheMode(
(CacheStoreMode) value,
determineCacheRetrieveMode( properties )
)
);
break;
case CRITERIA_COPY_TREE:
setCriteriaCopyTreeEnabled( Boolean.parseBoolean( value.toString() ) );
setCriteriaCopyTreeEnabled( parseBoolean( value.toString() ) );
break;
}
}
private Map<String, Object> computeCurrentSessionProperties() {
final HashMap<String, Object> map = new HashMap<>( fastSessionServices.defaultSessionProperties );
final Map<String, Object> map = new HashMap<>( fastSessionServices.defaultSessionProperties );
//The FLUSH_MODE is always set at Session creation time,
//so it needs special treatment to not eagerly initialize this Map:
map.put( AvailableSettings.FLUSH_MODE, getHibernateFlushMode().name() );
map.put( FLUSH_MODE, getHibernateFlushMode().name() );
return map;
}
@ -2687,7 +2686,7 @@ public class SessionImpl
if ( properties == null ) {
properties = computeCurrentSessionProperties();
}
return Collections.unmodifiableMap( properties );
return unmodifiableMap( properties );
}
@Override
@ -2734,8 +2733,8 @@ public class SessionImpl
try {
return createStoredProcedureCall( procedureName, resultSetMappings );
}
catch (UnknownSqlResultSetMappingException unknownResultSetMapping) {
throw new IllegalArgumentException( unknownResultSetMapping.getMessage(), unknownResultSetMapping );
catch ( UnknownSqlResultSetMappingException e ) {
throw new IllegalArgumentException( e.getMessage(), e );
}
}
catch ( RuntimeException e ) {
@ -2754,10 +2753,10 @@ public class SessionImpl
try {
getTransactionCoordinator().explicitJoin();
}
catch (TransactionRequiredForJoinException e) {
catch ( TransactionRequiredForJoinException e ) {
throw new TransactionRequiredException( e.getMessage() );
}
catch (HibernateException he) {
catch ( HibernateException he ) {
throw getExceptionConverter().convert( he );
}
}
@ -2902,12 +2901,12 @@ public class SessionImpl
return readOnly;
}
@Override
@Override @Deprecated(forRemoval = true)
public boolean isEnforcingFetchGraph() {
return this.isEnforcingFetchGraph;
return isEnforcingFetchGraph;
}
@Override
@Override @Deprecated(forRemoval = true)
public void setEnforcingFetchGraph(boolean isEnforcingFetchGraph) {
this.isEnforcingFetchGraph = isEnforcingFetchGraph;
}

View File

@ -26,11 +26,8 @@ import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.spi.EventSource;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.generator.Generator;
import org.hibernate.generator.BeforeExecutionGenerator;
@ -44,6 +41,8 @@ import static org.hibernate.engine.internal.Versioning.incrementVersion;
import static org.hibernate.engine.internal.Versioning.seedVersion;
import static org.hibernate.engine.internal.Versioning.setVersion;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.pretty.MessageHelper.infoString;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/**
* Concrete implementation of the {@link StatelessSession} API.
@ -129,9 +128,9 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public void delete(String entityName, Object entity) {
checkOpen();
EntityPersister persister = getEntityPersister( entityName, entity );
Object id = persister.getIdentifier( entity, this );
Object version = persister.getVersion( entity );
final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
final Object version = persister.getVersion( entity );
persister.delete( id, version, entity, this );
}
@ -147,13 +146,13 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public void update(String entityName, Object entity) {
checkOpen();
EntityPersister persister = getEntityPersister( entityName, entity );
Object id = persister.getIdentifier( entity, this );
Object[] state = persister.getValues( entity );
Object oldVersion;
final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
final Object[] state = persister.getValues( entity );
final Object oldVersion;
if ( persister.isVersioned() ) {
oldVersion = persister.getVersion( entity );
Object newVersion = incrementVersion( entity, oldVersion, persister, this );
final Object newVersion = incrementVersion( entity, oldVersion, persister, this );
setVersion( state, newVersion, persister );
persister.setValues( entity, state );
}
@ -185,9 +184,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public Object get(String entityName, Object id, LockMode lockMode) {
checkOpen();
final EntityPersister entityDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
final EntityPersister entityDescriptor = getEntityPersister( entityName );
final Object result = entityDescriptor.load( id, null, getNullSafeLockMode( lockMode ), this );
if ( temporaryPersistenceContext.isLoadFinished() ) {
@ -196,6 +193,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return result;
}
private EntityPersister getEntityPersister(String entityName) {
return getFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor( entityName );
}
@Override
public void refresh(Object entity) {
refresh( bestGuessEntityName( entity ), entity, LockMode.NONE );
@ -213,20 +214,11 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public void refresh(String entityName, Object entity, LockMode lockMode) {
final EntityPersister persister = this.getEntityPersister( entityName, entity );
final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Refreshing transient {0}", MessageHelper.infoString( persister, id, this.getFactory() ) );
LOG.tracev( "Refreshing transient {0}", infoString( persister, id, getFactory() ) );
}
// TODO : can this ever happen???
// EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
// if ( source.getPersistenceContext().getEntry( key ) != null ) {
// throw new PersistentObjectException(
// "attempted to refresh transient instance when persistent " +
// "instance was already associated with the Session: " +
// MessageHelper.infoString( persister, id, source.getFactory() )
// );
// }
if ( persister.canWriteToCache() ) {
final EntityDataAccess cacheAccess = persister.getCacheAccessStrategy();
@ -241,7 +233,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
String previousFetchProfile = getLoadQueryInfluencers().getInternalFetchProfile();
final String previousFetchProfile = getLoadQueryInfluencers().getInternalFetchProfile();
Object result;
try {
getLoadQueryInfluencers().setInternalFetchProfile( "refresh" );
@ -276,10 +268,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public Object instantiate(
String entityName,
Object id) throws HibernateException {
final EntityPersister entityDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
return instantiate( entityDescriptor, id );
return instantiate( getEntityPersister( entityName ), id );
}
@Override
@ -296,10 +285,8 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
boolean nullable) throws HibernateException {
checkOpen();
final EntityPersister entityDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
final EntityKey entityKey = generateEntityKey( id, entityDescriptor );
final EntityPersister persister = getEntityPersister( entityName );
final EntityKey entityKey = generateEntityKey( id, persister );
// first, try to load it from the temp PC associated to this SS
final PersistenceContext persistenceContext = getPersistenceContext();
@ -316,24 +303,24 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
// first, check to see if we can use "bytecode proxies"
final EntityMetamodel entityMetamodel = entityDescriptor.getEntityMetamodel();
final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata();
if ( bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) {
// if the entity defines a HibernateProxy factory, see if there is an
// existing proxy associated with the PC - and if so, use it
if ( entityDescriptor.getRepresentationStrategy().getProxyFactory() != null ) {
if ( persister.getRepresentationStrategy().getProxyFactory() != null ) {
final Object proxy = persistenceContext.getProxy( entityKey );
if ( proxy != null ) {
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Entity proxy found in session cache" );
}
if ( LOG.isDebugEnabled() && HibernateProxy.extractLazyInitializer( proxy ).isUnwrap() ) {
if ( LOG.isDebugEnabled() && extractLazyInitializer( proxy ).isUnwrap() ) {
LOG.debug( "Ignoring NO_PROXY to honor laziness" );
}
return persistenceContext.narrowProxy( proxy, entityDescriptor, entityKey, null );
return persistenceContext.narrowProxy( proxy, persister, entityKey, null );
}
// specialized handling for entities with subclasses with a HibernateProxy factory
@ -352,10 +339,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
// The entity will get loaded below.
}
else {
if ( entityDescriptor.hasProxy() ) {
if ( persister.hasProxy() ) {
final Object existingProxy = persistenceContext.getProxy( entityKey );
if ( existingProxy != null ) {
return persistenceContext.narrowProxy( existingProxy, entityDescriptor, entityKey, null );
return persistenceContext.narrowProxy( existingProxy, persister, entityKey, null );
}
else {
return createProxy( entityKey );
@ -387,7 +374,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public void fetch(Object association) {
checkOpen();
PersistenceContext persistenceContext = getPersistenceContext();
final LazyInitializer initializer = HibernateProxy.extractLazyInitializer( association );
final LazyInitializer initializer = extractLazyInitializer( association );
if ( initializer != null ) {
if ( initializer.isUninitialized() ) {
String entityName = initializer.getEntityName();
@ -411,9 +398,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
else if ( isPersistentAttributeInterceptable( association ) ) {
final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( association ).$$_hibernate_getInterceptor();
final PersistentAttributeInterceptor interceptor =
asPersistentAttributeInterceptable( association ).$$_hibernate_getInterceptor();
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor) {
EnhancementAsProxyLazinessInterceptor proxyInterceptor =
final EnhancementAsProxyLazinessInterceptor proxyInterceptor =
(EnhancementAsProxyLazinessInterceptor) interceptor;
proxyInterceptor.setSession( this );
try {
@ -428,13 +416,13 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
else if ( association instanceof PersistentCollection ) {
PersistentCollection<?> persistentCollection = (PersistentCollection<?>) association;
final PersistentCollection<?> persistentCollection = (PersistentCollection<?>) association;
if ( !persistentCollection.wasInitialized() ) {
final CollectionPersister collectionDescriptor = getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getCollectionDescriptor( persistentCollection.getRole() );
Object key = persistentCollection.getKey();
final Object key = persistentCollection.getKey();
persistenceContext.addUninitializedCollection( collectionDescriptor, persistentCollection, key );
persistentCollection.setCurrentSession(this);
try {
@ -460,7 +448,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return isAutoCloseSessionEnabled() && !isClosed();
}
private boolean isFlushModeNever() {
return false;
}
@ -479,31 +466,13 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public String bestGuessEntityName(Object object) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final LazyInitializer lazyInitializer = extractLazyInitializer( object );
if ( lazyInitializer != null ) {
object = lazyInitializer.getImplementation();
}
return guessEntityName( object );
}
// @Override
// public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// queryParameters.validateParameters();
// HQLQueryPlan plan = getQueryPlan( query, false );
// boolean success = false;
// int result = 0;
// try {
// result = plan.performExecuteUpdate( queryParameters, this );
// success = true;
// }
// finally {
// afterOperation( success );
// }
// temporaryPersistenceContext.clear();
// return result;
// }
@Override
public CacheMode getCacheMode() {
return CacheMode.IGNORE;
@ -535,17 +504,9 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public EntityPersister getEntityPersister(String entityName, Object object)
throws HibernateException {
checkOpen();
if ( entityName == null ) {
return getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( guessEntityName( object ) );
}
else {
return getFactory().getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName )
.getSubclassEntityPersister( object, getFactory() );
}
return entityName == null
? getEntityPersister( guessEntityName(object) )
: getEntityPersister( entityName ).getSubclassEntityPersister( object, getFactory() );
}
@Override
@ -582,16 +543,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return null;
}
@Override
public boolean isEventSource() {
return false;
}
@Override
public EventSource asEventSource() {
throw new HibernateException( "Illegal Cast to EventSource - guard by invoking isEventSource() first" );
}
public boolean isDefaultReadOnly() {
return false;
}
@ -606,23 +557,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
//TODO: COPY/PASTE FROM SessionImpl, pull up!
// @Override
// public List list(String query, QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// queryParameters.validateParameters();
// HQLQueryPlan plan = getQueryPlan( query, false );
// boolean success = false;
// List results = Collections.EMPTY_LIST;
// try {
// results = plan.performList( queryParameters, this );
// success = true;
// }
// finally {
// afterOperation( success );
// }
// temporaryPersistenceContext.clear();
// return results;
// }
public void afterOperation(boolean success) {
temporaryPersistenceContext.clear();
@ -656,30 +590,8 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return false;
}
// @Override
// public int executeNativeUpdate(
// NativeSQLQuerySpecification nativeSQLQuerySpecification,
// QueryParameters queryParameters) throws HibernateException {
// checkOpen();
// queryParameters.validateParameters();
// NativeSQLQueryPlan plan = getNativeQueryPlan( nativeSQLQuerySpecification );
//
// boolean success = false;
// int result = 0;
// try {
// result = plan.performExecuteUpdate( queryParameters, this );
// success = true;
// }
// finally {
// afterOperation( success );
// }
// temporaryPersistenceContext.clear();
// return result;
// }
@Override
public void afterTransactionBegin() {
}
@Override
@ -703,14 +615,11 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public void flushBeforeTransactionCompletion() {
boolean flush;
try {
flush = (
!isClosed()
&& !isFlushModeNever()
&& !JtaStatusHelper.isRollback(
getJtaPlatform().getCurrentStatus()
) );
flush = !isClosed()
&& !isFlushModeNever()
&& !JtaStatusHelper.isRollback( getJtaPlatform().getCurrentStatus() );
}
catch (SystemException se) {
catch ( SystemException se ) {
throw new HibernateException( "could not determine transaction status in beforeCompletion()", se );
}
if ( flush ) {

View File

@ -77,8 +77,7 @@ public class CacheEntityLoaderHelper {
// this object was already loaded
EntityEntry oldEntry = session.getPersistenceContext().getEntry( old );
if ( options.isCheckDeleted() ) {
Status status = oldEntry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
if ( oldEntry.getStatus().isDeletedOrGone() ) {
LoadingLogger.LOGGER.debug(
"Load request found matching entity in context, but it is scheduled for removal; returning null" );
return new PersistenceContextEntry( old, EntityStatus.REMOVED_ENTITY_MARKER );
@ -136,8 +135,7 @@ public class CacheEntityLoaderHelper {
// this object was already loaded
EntityEntry oldEntry = session.getPersistenceContext().getEntry( old );
if ( options.isCheckDeleted() ) {
Status status = oldEntry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
if ( oldEntry.getStatus().isDeletedOrGone() ) {
LoadingLogger.LOGGER.debug(
"Load request found matching entity in context, but it is scheduled for removal; returning null" );
return new PersistenceContextEntry( old, EntityStatus.REMOVED_ENTITY_MARKER );

View File

@ -209,7 +209,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) {
// make sure it is not DELETED
final EntityEntry entry = persistenceContext.getEntry( entity );
if ( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE ) {
if ( entry.getStatus().isDeletedOrGone() ) {
// the entity is locally deleted, and the options ask that we not return such entities...
entity = null;
}

View File

@ -134,7 +134,7 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, Jav
String entityName = entityPersister.getEntityName();
Boolean readOnly = this.readOnly != null ? this.readOnly : loadQueryInfluencers.getReadOnly();
if ( this.lockOptions != null ) {
if ( lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityName, lockOptions, eventSource, readOnly );
context.fireLoad( event, LoadEventListener.LOAD );
return (T) event.getResult();
@ -179,7 +179,7 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, Jav
String entityName = entityPersister.getEntityName();
Boolean readOnly = this.readOnly != null ? this.readOnly : loadQueryInfluencers.getReadOnly();
if ( this.lockOptions != null ) {
if ( lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityName, lockOptions, eventSource, readOnly );
context.fireLoad( event, LoadEventListener.GET );
final Object result = event.getResult();

View File

@ -692,8 +692,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
// todo (6.0): do we really need this check ?
if ( entry != null ) {
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
if ( entry.getStatus().isDeletedOrGone() ) {
return;
}
}

View File

@ -431,7 +431,7 @@ public class MultiLoadTest {
final EntityEntry entry = session.getPersistenceContext()
.getEntry( deletedEntity );
assertTrue( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE );
assertTrue( entry.getStatus().isDeletedOrGone() );
final int paramCount = StringHelper.countUnquoted(
statementInspector.getSqlQueries().get( 0 ),
@ -496,9 +496,8 @@ public class MultiLoadTest {
.equals( 2 ) ).findAny().orElse( null );
assertNotNull( deletedEntity );
final EntityEntry entry = ( (SharedSessionContractImplementor) session ).getPersistenceContext()
.getEntry( deletedEntity );
assertTrue( entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE );
final EntityEntry entry = session.getPersistenceContext().getEntry( deletedEntity );
assertTrue( entry.getStatus().isDeletedOrGone() );
final int paramCount = StringHelper.countUnquoted(
statementInspector.getSqlQueries().get( 0 ),