many misc cleanups and doc for the Session hierarchy
This commit is contained in:
parent
974fe9e22d
commit
fc62f33a55
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -18,5 +18,9 @@ public enum Status {
|
|||
DELETED,
|
||||
GONE,
|
||||
LOADING,
|
||||
SAVING
|
||||
SAVING;
|
||||
|
||||
public boolean isDeletedOrGone() {
|
||||
return this == DELETED || this == GONE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ),
|
||||
|
|
Loading…
Reference in New Issue