HHH-13154 Add support for JPA criteria on stateless sessions

This commit is contained in:
Yoann Rodière 2019-02-08 11:10:23 +01:00
parent fd1963a6a2
commit 6b199d2e52
11 changed files with 178 additions and 100 deletions

View File

@ -1164,12 +1164,15 @@ public interface Session extends SharedSessionContract, EntityManager, Hibernate
@Override
<T> org.hibernate.query.Query<T> createQuery(String queryString, Class<T> resultType);
// Override the JPA return type with the one exposed in QueryProducer
@Override
<T> org.hibernate.query.Query<T> createQuery(CriteriaQuery<T> criteriaQuery);
// Override the JPA return type with the one exposed in QueryProducer
@Override
org.hibernate.query.Query createQuery(CriteriaUpdate updateQuery);
// Override the JPA return type with the one exposed in QueryProducer
@Override
org.hibernate.query.Query createQuery(CriteriaDelete deleteQuery);

View File

@ -13,6 +13,7 @@ import java.util.List;
import java.util.UUID;
import javax.persistence.FlushModeType;
import javax.persistence.TransactionRequiredException;
import javax.persistence.criteria.Selection;
import org.hibernate.CacheMode;
import org.hibernate.Criteria;
@ -30,8 +31,10 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.QueryProducerImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
@ -489,4 +492,16 @@ public interface SharedSessionContractImplementor
) :
sessionJdbcBatchSize;
}
/**
* @deprecated (since 5.2) - see deprecation note on
* org.hibernate.jpa.spi.HibernateEntityManagerImplementor#createQuery(java.lang.String, java.lang.Class, javax.persistence.criteria.Selection, org.hibernate.jpa.spi.HibernateEntityManagerImplementor.QueryOptions)
* @return The typed query
*/
@Deprecated
<T> QueryImplementor<T> createQuery(
String jpaqlString,
Class<T> resultClass,
Selection selection,
HibernateEntityManagerImplementor.QueryOptions queryOptions);
}

View File

@ -17,6 +17,10 @@ import java.util.UUID;
import javax.persistence.FlushModeType;
import javax.persistence.TransactionRequiredException;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Selection;
import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode;
@ -63,6 +67,8 @@ import org.hibernate.engine.transaction.internal.TransactionImpl;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.id.uuid.StandardRandomStrategy;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.jpa.spi.TupleBuilderTransformer;
import org.hibernate.persister.entity.EntityPersister;
@ -71,6 +77,9 @@ import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.internal.ProcedureCallImpl;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.Query;
import org.hibernate.query.criteria.internal.compile.CompilableCriteria;
import org.hibernate.query.criteria.internal.compile.CriteriaCompiler;
import org.hibernate.query.criteria.internal.expression.CompoundSelectionImpl;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.query.internal.QueryImpl;
import org.hibernate.query.spi.NativeQueryImplementor;
@ -140,6 +149,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
protected transient ExceptionConverter exceptionConverter;
private CriteriaCompiler criteriaCompiler;
public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreationOptions options) {
this.factory = factory;
this.cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this );
@ -730,6 +741,81 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
}
}
@SuppressWarnings("WeakerAccess")
protected CriteriaCompiler criteriaCompiler() {
if ( criteriaCompiler == null ) {
criteriaCompiler = new CriteriaCompiler( this );
}
return criteriaCompiler;
}
@Override
@SuppressWarnings("unchecked")
public <T> QueryImplementor<T> createQuery(CriteriaQuery<T> criteriaQuery) {
checkOpen();
try {
return (QueryImplementor<T>) criteriaCompiler().compile( (CompilableCriteria) criteriaQuery );
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
@Override
public QueryImplementor createQuery(CriteriaUpdate criteriaUpdate) {
checkOpen();
try {
return criteriaCompiler().compile( (CompilableCriteria) criteriaUpdate );
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
@Override
public QueryImplementor createQuery(CriteriaDelete criteriaDelete) {
checkOpen();
try {
return criteriaCompiler().compile( (CompilableCriteria) criteriaDelete );
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
@Override
@SuppressWarnings("unchecked")
public <T> QueryImplementor<T> createQuery(
String jpaqlString,
Class<T> resultClass,
Selection selection,
HibernateEntityManagerImplementor.QueryOptions queryOptions) {
try {
final QueryImplementor query = createQuery( jpaqlString );
if ( queryOptions.getValueHandlers() == null ) {
if ( queryOptions.getResultMetadataValidator() != null ) {
queryOptions.getResultMetadataValidator().validate( query.getReturnTypes() );
}
}
// determine if we need a result transformer
List tupleElements = Tuple.class.equals( resultClass )
? ( (CompoundSelectionImpl<Tuple>) selection ).getCompoundSelectionItems()
: null;
if ( queryOptions.getValueHandlers() != null || tupleElements != null ) {
query.setResultTransformer(
new CriteriaQueryTupleTransformer( queryOptions.getValueHandlers(), tupleElements )
);
}
return query;
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
protected void applyQuerySettingsAndHints(Query query) {
}

View File

@ -39,12 +39,7 @@ import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockScope;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TransactionRequiredException;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Selection;
import org.hibernate.CacheMode;
import org.hibernate.Criteria;
@ -154,7 +149,6 @@ 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;
import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader;
@ -173,11 +167,7 @@ import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.Query;
import org.hibernate.query.criteria.internal.compile.CompilableCriteria;
import org.hibernate.query.criteria.internal.compile.CriteriaCompiler;
import org.hibernate.query.criteria.internal.expression.CompoundSelectionImpl;
import org.hibernate.query.internal.CollectionFilterImpl;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.resource.transaction.TransactionRequiredForJoinException;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl;
@ -3476,39 +3466,6 @@ public final class SessionImpl
}
}
@Override
@SuppressWarnings("unchecked")
public <T> QueryImplementor<T> createQuery(
String jpaqlString,
Class<T> resultClass,
Selection selection,
QueryOptions queryOptions) {
try {
final QueryImplementor query = createQuery( jpaqlString );
if ( queryOptions.getValueHandlers() == null ) {
if ( queryOptions.getResultMetadataValidator() != null ) {
queryOptions.getResultMetadataValidator().validate( query.getReturnTypes() );
}
}
// determine if we need a result transformer
List tupleElements = Tuple.class.equals( resultClass )
? ( (CompoundSelectionImpl<Tuple>) selection ).getCompoundSelectionItems()
: null;
if ( queryOptions.getValueHandlers() != null || tupleElements != null ) {
query.setResultTransformer(
new CriteriaQueryTupleTransformer( queryOptions.getValueHandlers(), tupleElements )
);
}
return query;
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EntityManager impl
@ -3765,50 +3722,6 @@ public final class SessionImpl
return Collections.unmodifiableMap( properties );
}
private CriteriaCompiler criteriaCompiler;
@SuppressWarnings("WeakerAccess")
protected CriteriaCompiler criteriaCompiler() {
if ( criteriaCompiler == null ) {
criteriaCompiler = new CriteriaCompiler( this );
}
return criteriaCompiler;
}
@Override
@SuppressWarnings("unchecked")
public <T> QueryImplementor<T> createQuery(CriteriaQuery<T> criteriaQuery) {
checkOpen();
try {
return (QueryImplementor<T>) criteriaCompiler().compile( (CompilableCriteria) criteriaQuery );
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
@Override
public QueryImplementor createQuery(CriteriaUpdate criteriaUpdate) {
checkOpen();
try {
return criteriaCompiler().compile( (CompilableCriteria) criteriaUpdate );
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
@Override
public QueryImplementor createQuery(CriteriaDelete criteriaDelete) {
checkOpen();
try {
return criteriaCompiler().compile( (CompilableCriteria) criteriaDelete );
}
catch ( RuntimeException e ) {
throw exceptionConverter.convert( e );
}
}
@Override
protected void initQueryFromNamedDefinition(Query query, NamedQueryDefinition namedQueryDefinition) {
super.initQueryFromNamedDefinition( query, namedQueryDefinition );

View File

@ -8,6 +8,10 @@ package org.hibernate.query;
import org.hibernate.SQLQuery;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
/**
* Contract for things that can produce Query instances. Expected implementors include
* Session and StatelessSession.
@ -163,4 +167,10 @@ public interface QueryProducer {
* @return The NativeQuery instance for manipulation and execution
*/
NativeQuery getNamedNativeQuery(String name);
<T> Query<T> createQuery(CriteriaQuery<T> criteriaQuery);
Query createQuery(CriteriaUpdate updateQuery);
Query createQuery(CriteriaDelete deleteQuery);
}

View File

@ -17,6 +17,7 @@ import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.EntityType;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.query.criteria.internal.compile.CompilableCriteria;
import org.hibernate.query.criteria.internal.compile.CriteriaInterpretation;
@ -105,7 +106,7 @@ public abstract class AbstractManipulationCriteriaQuery<T> implements Compilable
@Override
@SuppressWarnings("unchecked")
public QueryImplementor buildCompiledQuery(
SessionImplementor entityManager,
SharedSessionContractImplementor entityManager,
final InterpretedParameterMetadata interpretedParameterMetadata) {
final Map<String,Class> implicitParameterTypes = extractTypeMap( interpretedParameterMetadata.implicitParameterBindings() );

View File

@ -24,7 +24,7 @@ import javax.persistence.criteria.Selection;
import javax.persistence.criteria.Subquery;
import javax.persistence.metamodel.EntityType;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.query.criteria.internal.compile.CompilableCriteria;
import org.hibernate.query.criteria.internal.compile.CriteriaInterpretation;
@ -302,7 +302,7 @@ public class CriteriaQueryImpl<T> extends AbstractNode implements CriteriaQuery<
@Override
@SuppressWarnings("unchecked")
public QueryImplementor buildCompiledQuery(
SessionImplementor entityManager,
SharedSessionContractImplementor entityManager,
final InterpretedParameterMetadata parameterMetadata) {
final Map<String,Class> implicitParameterTypes = extractTypeMap( parameterMetadata.implicitParameterBindings() );

View File

@ -14,11 +14,10 @@ import java.util.Map;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.ParameterExpression;
import org.hibernate.SessionFactory;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
@ -38,9 +37,9 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class CriteriaCompiler implements Serializable {
private final SessionImplementor entityManager;
private final SharedSessionContractImplementor entityManager;
public CriteriaCompiler(SessionImplementor entityManager) {
public CriteriaCompiler(SharedSessionContractImplementor entityManager) {
this.entityManager = entityManager;
}
@ -55,7 +54,7 @@ public class CriteriaCompiler implements Serializable {
final Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap = new HashMap<>();
final List<ImplicitParameterBinding> implicitParameterBindings = new ArrayList<>();
final SessionFactoryImplementor sessionFactory = entityManager.getSessionFactory();
final SessionFactoryImplementor sessionFactory = entityManager.getFactory();
final LiteralHandlingMode criteriaLiteralHandlingMode = sessionFactory
.getSessionFactoryOptions()

View File

@ -6,7 +6,7 @@
*/
package org.hibernate.query.criteria.internal.compile;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.spi.QueryImplementor;
/**
@ -25,5 +25,5 @@ public interface CriteriaInterpretation {
*
* @return The created Query instance.
*/
QueryImplementor buildCompiledQuery(SessionImplementor entityManager, InterpretedParameterMetadata interpretedParameterMetadata);
QueryImplementor buildCompiledQuery(SharedSessionContractImplementor entityManager, InterpretedParameterMetadata interpretedParameterMetadata);
}

View File

@ -36,7 +36,7 @@ import org.hibernate.Query;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.RootGraph;
import org.hibernate.query.ParameterMetadata;
@ -59,12 +59,12 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public class CriteriaQueryTypeQueryAdapter<X> implements QueryImplementor<X> {
private final SessionImplementor entityManager;
private final SharedSessionContractImplementor entityManager;
private final QueryImplementor<X> jpqlQuery;
private final Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap;
public CriteriaQueryTypeQueryAdapter(
SessionImplementor entityManager,
SharedSessionContractImplementor entityManager,
QueryImplementor<X> jpqlQuery,
Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap) {
this.entityManager = entityManager;

View File

@ -42,6 +42,21 @@ public class BasicCriteriaExecutionTests extends BaseNonConfigCoreFunctionalTest
);
}
@Test
public void testExecutingBasicCriteriaQueryInStatelessSession() {
final CriteriaBuilder criteriaBuilder = sessionFactory().getCriteriaBuilder();
final CriteriaQuery<Object> criteria = criteriaBuilder.createQuery();
final Root<BasicEntity> root = criteria.from( BasicEntity.class );
criteria.select( root );
inStatelessSession(
session -> session.createQuery( criteria ).list()
);
}
@Test
public void testExecutingBasicCriteriaQueryLiteralPredicate() {
final CriteriaBuilder criteriaBuilder = sessionFactory().getCriteriaBuilder();
@ -59,6 +74,23 @@ public class BasicCriteriaExecutionTests extends BaseNonConfigCoreFunctionalTest
);
}
@Test
public void testExecutingBasicCriteriaQueryLiteralPredicateInStatelessSession() {
final CriteriaBuilder criteriaBuilder = sessionFactory().getCriteriaBuilder();
final CriteriaQuery<Object> criteria = criteriaBuilder.createQuery();
final Root<BasicEntity> root = criteria.from( BasicEntity.class );
criteria.select( root );
criteria.where( criteriaBuilder.equal( criteriaBuilder.literal( 1 ), criteriaBuilder.literal( 1 ) ) );
inStatelessSession(
session -> session.createQuery( criteria ).list()
);
}
@Test
public void testExecutingBasicCriteriaQueryParameterPredicate() {
final CriteriaBuilder criteriaBuilder = sessionFactory().getCriteriaBuilder();
@ -78,6 +110,25 @@ public class BasicCriteriaExecutionTests extends BaseNonConfigCoreFunctionalTest
);
}
@Test
public void testExecutingBasicCriteriaQueryParameterPredicateInStatelessSession() {
final CriteriaBuilder criteriaBuilder = sessionFactory().getCriteriaBuilder();
final CriteriaQuery<Object> criteria = criteriaBuilder.createQuery();
final Root<BasicEntity> root = criteria.from( BasicEntity.class );
criteria.select( root );
final ParameterExpression<Integer> param = criteriaBuilder.parameter( Integer.class );
criteria.where( criteriaBuilder.equal( param, param ) );
inStatelessSession(
session -> session.createQuery( criteria ).setParameter( param, 1 ).list()
);
}
@Entity
public static class BasicEntity {