HHH-16913 EntityGraph support for StatelessSession

This commit is contained in:
Gavin King 2023-07-08 16:38:33 +02:00
parent 6b7d5bae3d
commit 294ec27885
7 changed files with 176 additions and 56 deletions

View File

@ -8,7 +8,10 @@ package org.hibernate;
import java.io.Closeable;
import java.io.Serializable;
import java.util.List;
import jakarta.persistence.EntityGraph;
import org.hibernate.graph.RootGraph;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.procedure.ProcedureCall;
@ -240,6 +243,48 @@ public interface SharedSessionContract extends QueryProducer, Closeable, Seriali
throw new UnsupportedOperationException();
}
/**
* Create a new mutable {@link EntityGraph} with only a root node.
*
* @since 6.3
*/
<T> RootGraph<T> createEntityGraph(Class<T> rootType);
/**
* Create a new mutable copy of the named {@link EntityGraph},
* or return {@code null} if there is no graph with the given
* name.
*
* @param graphName the name of the graph
*
* @see jakarta.persistence.EntityManagerFactory#addNamedEntityGraph(String, EntityGraph)
*
* @since 6.3
*/
RootGraph<?> createEntityGraph(String graphName);
/**
* Retrieve the named {@link EntityGraph} as an immutable graph,
* or return {@code null} if there is no graph with the given
* name.
*
* @see jakarta.persistence.EntityManagerFactory#addNamedEntityGraph(String, EntityGraph)
*
* @param graphName the name of the graph
*
* @since 6.3
*/
RootGraph<?> getEntityGraph(String graphName);
/**
* Retrieve all named {@link EntityGraph}s with the given type.
*
* @see jakarta.persistence.EntityManagerFactory#addNamedEntityGraph(String, EntityGraph)
*
* @since 6.3
*/
<T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass);
/**
* The factory which created this session.
*/

View File

@ -6,6 +6,9 @@
*/
package org.hibernate;
import jakarta.persistence.EntityGraph;
import org.hibernate.graph.GraphSemantic;
/**
* A command-oriented API often used for performing bulk operations against
* the database. A stateless session has no persistence context, and always
@ -163,6 +166,38 @@ public interface StatelessSession extends SharedSessionContract {
*/
<T> T get(Class<T> entityClass, Object id, LockMode lockMode);
/**
* Retrieve a row, fetching associations specified by the
* given {@link EntityGraph}.
*
* @param graph The {@link EntityGraph}
* @param graphSemantic a {@link GraphSemantic} specifying
* how the graph should be interpreted
* @param id The id of the entity to retrieve
*
* @return a detached entity instance
*
* @since 6.3
*/
<T> T get(EntityGraph<T> graph, GraphSemantic graphSemantic, Object id);
/**
* Retrieve a row, fetching associations specified by the
* given {@link EntityGraph}, and obtaining the specified
* lock mode.
*
* @param graph The {@link EntityGraph}
* @param graphSemantic a {@link GraphSemantic} specifying
* how the graph should be interpreted
* @param id The id of the entity to retrieve
* @param lockMode The lock mode to apply to the entity
*
* @return a detached entity instance
*
* @since 6.3
*/
<T> T get(EntityGraph<T> graph, GraphSemantic graphSemantic, Object id, LockMode lockMode);
/**
* Refresh the entity instance state from the database.
*

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.engine.spi;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
@ -22,6 +23,7 @@ import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.graph.RootGraph;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.persister.entity.EntityPersister;
@ -36,6 +38,7 @@ import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
@ -593,4 +596,24 @@ public class SharedSessionDelegatorBaseImpl implements SharedSessionContractImpl
public TimeZone getJdbcTimeZone() {
return delegate.getJdbcTimeZone();
}
@Override
public <T> RootGraph<T> createEntityGraph(Class<T> rootType) {
return delegate.createEntityGraph( rootType );
}
@Override
public RootGraph<?> createEntityGraph(String graphName) {
return delegate.createEntityGraph( graphName );
}
@Override
public RootGraph<?> getEntityGraph(String graphName) {
return delegate.getEntityGraph( graphName );
}
@Override
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
return delegate.getEntityGraphs( entityClass );
}
}

View File

@ -32,7 +32,6 @@ import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;

View File

@ -17,6 +17,7 @@ import java.util.TimeZone;
import java.util.UUID;
import java.util.function.Function;
import jakarta.persistence.EntityGraph;
import org.hibernate.CacheMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.FlushMode;
@ -41,6 +42,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.transaction.internal.TransactionImpl;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.graph.internal.RootGraphImpl;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.id.uuid.StandardRandomStrategy;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
@ -1373,6 +1376,38 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
return query;
}
@Override
public <T> RootGraphImplementor<T> createEntityGraph(Class<T> rootType) {
checkOpen();
return new RootGraphImpl<>( null, getFactory().getJpaMetamodel().entity( rootType ) );
}
@Override
public RootGraphImplementor<?> createEntityGraph(String graphName) {
checkOpen();
final RootGraphImplementor<?> named = getFactory().findEntityGraphByName( graphName );
if ( named == null ) {
return null;
}
return named.makeRootGraph( graphName, true );
}
@Override
public RootGraphImplementor<?> getEntityGraph(String graphName) {
checkOpen();
final RootGraphImplementor<?> named = getFactory().findEntityGraphByName( graphName );
if ( named == null ) {
throw new IllegalArgumentException( "Could not locate EntityGraph with given name : " + graphName );
}
return named;
}
@Override
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
checkOpen();
return getFactory().findEntityGraphsByType( entityClass );
}
private void writeObject(ObjectOutputStream oos) throws IOException {
if ( log.isTraceEnabled() ) {
log.trace( "Serializing " + getClass().getSimpleName() + " [" );

View File

@ -2860,38 +2860,6 @@ public class SessionImpl
return getFactory().getJpaMetamodel();
}
@Override
public <T> RootGraphImplementor<T> createEntityGraph(Class<T> rootType) {
checkOpen();
return new RootGraphImpl<>( null, getFactory().getJpaMetamodel().entity( rootType ) );
}
@Override
public RootGraphImplementor<?> createEntityGraph(String graphName) {
checkOpen();
final RootGraphImplementor<?> named = getEntityManagerFactory().findEntityGraphByName( graphName );
if ( named == null ) {
return null;
}
return named.makeRootGraph( graphName, true );
}
@Override
public RootGraphImplementor<?> getEntityGraph(String graphName) {
checkOpen();
final RootGraphImplementor<?> named = getEntityManagerFactory().findEntityGraphByName( graphName );
if ( named == null ) {
throw new IllegalArgumentException( "Could not locate EntityGraph with given name : " + graphName );
}
return named;
}
@Override
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
checkOpen();
return getEntityManagerFactory().findEntityGraphsByType( entityClass );
}
/**
* Used by JDK serialization...
*

View File

@ -8,6 +8,7 @@ package org.hibernate.internal;
import java.util.Set;
import jakarta.persistence.EntityGraph;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
@ -21,6 +22,7 @@ import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.spi.EffectiveEntityGraph;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
@ -28,6 +30,9 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable;
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.graph.GraphSemantic;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.LazyInitializer;
@ -63,24 +68,15 @@ import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
public class StatelessSessionImpl extends AbstractSharedSessionContract implements StatelessSession {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( StatelessSessionImpl.class );
private static final LoadQueryInfluencers NO_INFLUENCERS = new LoadQueryInfluencers() {
@Override @Deprecated
public String getInternalFetchProfile() {
return null;
}
@Override @Deprecated
public void setInternalFetchProfile(String internalFetchProfile) {
}
};
private final PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
private final LoadQueryInfluencers influencers;
private final PersistenceContext temporaryPersistenceContext;
private final boolean connectionProvided;
public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
super( factory, options );
connectionProvided = options.getConnection() != null;
temporaryPersistenceContext = new StatefulPersistenceContext( this );
influencers = new LoadQueryInfluencers( getFactory() );
}
@Override
@ -238,6 +234,30 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return result;
}
@Override
public <T> T get(EntityGraph<T> graph, GraphSemantic graphSemantic, Object id) {
return get( graph, graphSemantic, id, LockMode.NONE );
}
@Override @SuppressWarnings("unchecked")
public <T> T get(
EntityGraph<T> graph, GraphSemantic graphSemantic,
Object id, LockMode lockMode) {
final RootGraphImplementor<T> rootGraph = (RootGraphImplementor<T>) graph;
checkOpen();
final EffectiveEntityGraph effectiveEntityGraph =
getLoadQueryInfluencers().getEffectiveEntityGraph();
effectiveEntityGraph.applyGraph( rootGraph, graphSemantic );
try {
return (T) get( rootGraph.getGraphedType().getTypeName(), id, lockMode );
}
finally {
effectiveEntityGraph.clear();
}
}
private EntityPersister getEntityPersister(String entityName) {
return getFactory().getMappingMetamodel().getEntityDescriptor( entityName );
}
@ -278,15 +298,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
}
}
final String previousFetchProfile = getLoadQueryInfluencers().getInternalFetchProfile();
Object result;
try {
getLoadQueryInfluencers().setInternalFetchProfile( "refresh" );
result = persister.load( id, entity, getNullSafeLockMode( lockMode ), this );
}
finally {
getLoadQueryInfluencers().setInternalFetchProfile( previousFetchProfile );
}
final Object result = getLoadQueryInfluencers().fromInternalFetchProfile(
CascadingFetchProfile.REFRESH,
() -> persister.load( id, entity, getNullSafeLockMode( lockMode ), this )
);
UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
if ( temporaryPersistenceContext.isLoadFinished() ) {
temporaryPersistenceContext.clear();
@ -619,7 +634,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
@Override
public LoadQueryInfluencers getLoadQueryInfluencers() {
return NO_INFLUENCERS;
return influencers;
}
@Override