mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-03 08:19:15 +00:00
implement readonly loader feature
This commit is contained in:
parent
ced4f5e602
commit
23719ff481
@ -21,6 +21,7 @@
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryOptionsAdapter;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
@ -55,7 +56,7 @@ public SingleIdEntityLoaderDynamicBatch(
|
||||
}
|
||||
|
||||
@Override
|
||||
public T load(Object pkValue, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
||||
public T load(Object pkValue, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) {
|
||||
final Object[] batchIds = session.getPersistenceContextInternal()
|
||||
.getBatchFetchQueue()
|
||||
.getBatchLoadableEntityIds( getLoadable(), pkValue, maxBatchSize );
|
||||
@ -64,7 +65,7 @@ public T load(Object pkValue, LockOptions lockOptions, SharedSessionContractImpl
|
||||
if ( numberOfIds <= 1 ) {
|
||||
initializeSingleIdLoaderIfNeeded( session );
|
||||
|
||||
final T result = singleIdLoader.load( pkValue, lockOptions, session );
|
||||
final T result = singleIdLoader.load( pkValue, lockOptions, readOnly, session );
|
||||
if ( result == null ) {
|
||||
// There was no entity with the specified ID. Make sure the EntityKey does not remain
|
||||
// in the batch to avoid including it in future batches that get executed.
|
||||
@ -147,7 +148,12 @@ public SharedSessionContractImplementor getSession() {
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return QueryOptions.NONE;
|
||||
return new QueryOptionsAdapter() {
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,9 +187,10 @@ public T load(
|
||||
Object pkValue,
|
||||
Object entityInstance,
|
||||
LockOptions lockOptions,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) {
|
||||
initializeSingleIdLoaderIfNeeded( session );
|
||||
return singleIdLoader.load( pkValue, entityInstance, lockOptions, session );
|
||||
return singleIdLoader.load( pkValue, entityInstance, lockOptions, readOnly, session );
|
||||
}
|
||||
|
||||
private void initializeSingleIdLoaderIfNeeded(SharedSessionContractImplementor session) {
|
||||
|
@ -57,7 +57,7 @@ public EntityMappingType getLoadable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T load(Object pkValue, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
||||
public T load(Object pkValue, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) {
|
||||
//noinspection unchecked
|
||||
final QueryImplementor<T> query = namedQueryMemento.toQuery(
|
||||
session,
|
||||
@ -74,11 +74,12 @@ public T load(
|
||||
Object pkValue,
|
||||
Object entityInstance,
|
||||
LockOptions lockOptions,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( entityInstance != null ) {
|
||||
throw new UnsupportedOperationException( );
|
||||
}
|
||||
return load( pkValue, lockOptions, session );
|
||||
return load( pkValue, lockOptions, readOnly, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,14 +52,14 @@ public void prepare() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T load(Object key, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
||||
public T load(Object key, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) {
|
||||
final SingleIdLoadPlan<T> loadPlan = resolveLoadPlan(
|
||||
lockOptions,
|
||||
session.getLoadQueryInfluencers(),
|
||||
session.getFactory()
|
||||
);
|
||||
|
||||
return loadPlan.load( key, lockOptions, null, session );
|
||||
return loadPlan.load( key, lockOptions, readOnly, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -67,6 +67,7 @@ public T load(
|
||||
Object key,
|
||||
Object entityInstance,
|
||||
LockOptions lockOptions,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) {
|
||||
final SingleIdLoadPlan<T> loadPlan = resolveLoadPlan(
|
||||
lockOptions,
|
||||
@ -74,7 +75,7 @@ public T load(
|
||||
session.getFactory()
|
||||
);
|
||||
|
||||
return loadPlan.load( key, lockOptions, entityInstance, session );
|
||||
return loadPlan.load( key, lockOptions, entityInstance, readOnly, session );
|
||||
}
|
||||
|
||||
@Internal
|
||||
|
@ -18,6 +18,7 @@
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryOptionsAdapter;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
@ -73,14 +74,23 @@ public SelectStatement getSqlAst() {
|
||||
T load(
|
||||
Object restrictedValue,
|
||||
LockOptions lockOptions,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) {
|
||||
return load( restrictedValue, lockOptions, null, session );
|
||||
return load( restrictedValue, lockOptions, null, readOnly, session );
|
||||
}
|
||||
|
||||
T load(
|
||||
Object restrictedValue,
|
||||
LockOptions lockOptions,
|
||||
SharedSessionContractImplementor session) {
|
||||
return load( restrictedValue, lockOptions, null, null, session );
|
||||
}
|
||||
|
||||
T load(
|
||||
Object restrictedValue,
|
||||
LockOptions lockOptions,
|
||||
Object entityInstance,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) {
|
||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
@ -145,7 +155,12 @@ public Object getEntityId() {
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return QueryOptions.NONE;
|
||||
return new QueryOptionsAdapter() {
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,6 +22,7 @@
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryOptionsAdapter;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
@ -57,6 +58,7 @@ public EntityMappingType getLoadable() {
|
||||
public T load(
|
||||
Object ukValue,
|
||||
LockOptions lockOptions,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) {
|
||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||
|
||||
@ -117,7 +119,12 @@ public SharedSessionContractImplementor getSession() {
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return QueryOptions.NONE;
|
||||
return new QueryOptionsAdapter() {
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,4 +23,7 @@ public interface CollectionLoader extends Loader {
|
||||
* Load a collection by its key (not necessarily the same as its owner's PK).
|
||||
*/
|
||||
PersistentCollection load(Object key, SharedSessionContractImplementor session);
|
||||
|
||||
//TODO support 'readOnly' collection loading
|
||||
|
||||
}
|
||||
|
@ -22,5 +22,9 @@ public interface SingleEntityLoader<T> extends Loader {
|
||||
/**
|
||||
* Load an entity by a primary or unique key value.
|
||||
*/
|
||||
T load(Object key, LockOptions lockOptions, SharedSessionContractImplementor session);
|
||||
T load(Object key, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session);
|
||||
|
||||
default T load(Object key, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
||||
return load( key, lockOptions, session );
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,18 @@ public interface SingleIdEntityLoader<T> extends SingleEntityLoader<T> {
|
||||
* Load by primary key value
|
||||
*/
|
||||
@Override
|
||||
T load(Object pkValue, LockOptions lockOptions, SharedSessionContractImplementor session);
|
||||
T load(Object pkValue, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Load by primary key value, populating the passed entity instance. Used to initialize an uninitialized
|
||||
* bytecode-proxy or {@link org.hibernate.event.spi.LoadEvent} handling.
|
||||
* The passed instance is the enhanced proxy or the entity to be loaded.
|
||||
*/
|
||||
T load(Object pkValue, Object entityInstance, LockOptions lockOptions, SharedSessionContractImplementor session);
|
||||
T load(Object pkValue, Object entityInstance, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session);
|
||||
|
||||
default T load(Object pkValue, Object entityInstance, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
||||
return load( pkValue, entityInstance, lockOptions, null, session );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load database snapshot by primary key value
|
||||
|
@ -19,7 +19,7 @@ public interface SingleUniqueKeyEntityLoader<T> extends SingleEntityLoader {
|
||||
* Load by unique key value
|
||||
*/
|
||||
@Override
|
||||
T load(Object ukValue, LockOptions lockOptions, SharedSessionContractImplementor session);
|
||||
T load(Object ukValue, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Resolve the matching id
|
||||
|
@ -2617,7 +2617,15 @@ public Object loadByUniqueKey(
|
||||
String propertyName,
|
||||
Object uniqueKey,
|
||||
SharedSessionContractImplementor session) throws HibernateException {
|
||||
return getUniqueKeyLoader( propertyName ).load( uniqueKey, LockOptions.READ, session );
|
||||
return loadByUniqueKey( propertyName, uniqueKey, null, session );
|
||||
}
|
||||
|
||||
public Object loadByUniqueKey(
|
||||
String propertyName,
|
||||
Object uniqueKey,
|
||||
Boolean readOnly,
|
||||
SharedSessionContractImplementor session) throws HibernateException {
|
||||
return getUniqueKeyLoader( propertyName ).load( uniqueKey, LockOptions.READ, readOnly, session );
|
||||
}
|
||||
|
||||
private Map<SingularAttributeMapping, SingleUniqueKeyEntityLoader<?>> uniqueKeyLoadersNew;
|
||||
@ -4459,25 +4467,25 @@ public Object load(Object id, Object optionalObject, LockMode lockMode, SharedSe
|
||||
*/
|
||||
public Object load(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session)
|
||||
throws HibernateException {
|
||||
return doLoad( id, optionalObject, lockOptions, session, null );
|
||||
return doLoad( id, optionalObject, lockOptions, null, session );
|
||||
}
|
||||
|
||||
public Object load(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly)
|
||||
throws HibernateException {
|
||||
return doLoad( id, optionalObject, lockOptions, session, readOnly );
|
||||
return doLoad( id, optionalObject, lockOptions, readOnly, session );
|
||||
}
|
||||
|
||||
private Object doLoad(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly)
|
||||
private Object doLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session)
|
||||
throws HibernateException {
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Fetching entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
|
||||
}
|
||||
|
||||
if ( optionalObject == null ) {
|
||||
return singleIdEntityLoader.load( id, lockOptions, session );
|
||||
return singleIdEntityLoader.load( id, lockOptions, readOnly, session );
|
||||
}
|
||||
else {
|
||||
return singleIdEntityLoader.load( id, optionalObject, lockOptions, session );
|
||||
return singleIdEntityLoader.load( id, optionalObject, lockOptions, readOnly, session );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@
|
||||
* @since 5.2
|
||||
*/
|
||||
@Incubating
|
||||
public class ScrollableResultsIterator<T> implements CloseableIterator {
|
||||
private final ScrollableResultsImplementor scrollableResults;
|
||||
public class ScrollableResultsIterator<T> implements CloseableIterator<T> {
|
||||
private final ScrollableResultsImplementor<T> scrollableResults;
|
||||
|
||||
public ScrollableResultsIterator(ScrollableResultsImplementor scrollableResults) {
|
||||
public ScrollableResultsIterator(ScrollableResultsImplementor<T> scrollableResults) {
|
||||
this.scrollableResults = scrollableResults;
|
||||
}
|
||||
|
||||
@ -34,7 +34,6 @@ public boolean hasNext() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public T next() {
|
||||
return (T) scrollableResults.get();
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
package org.hibernate.query.spi;
|
||||
|
||||
import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.persistence.CacheRetrieveMode;
|
||||
import javax.persistence.CacheStoreMode;
|
||||
@ -184,85 +183,6 @@ default boolean hasLimit() {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
QueryOptions NONE = new QueryOptions() {
|
||||
@Override
|
||||
public Limit getLimit() {
|
||||
return Limit.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getFetchSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockOptions getLockOptions() {
|
||||
return LockOptions.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDatabaseHints() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlushMode getFlushMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheRetrieveMode getCacheRetrieveMode() {
|
||||
return CacheRetrieveMode.BYPASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheStoreMode getCacheStoreMode() {
|
||||
return CacheStoreMode.BYPASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheMode getCacheMode() {
|
||||
return CacheMode.IGNORE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isResultCachingEnabled() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultCacheRegionName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppliedGraph getAppliedGraph() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleTransformer getTupleTransformer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultListTransformer getResultListTransformer() {
|
||||
return null;
|
||||
}
|
||||
QueryOptions NONE = new QueryOptionsAdapter() {
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.spi;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.persistence.CacheRetrieveMode;
|
||||
import javax.persistence.CacheStoreMode;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.graph.spi.AppliedGraph;
|
||||
import org.hibernate.query.Limit;
|
||||
import org.hibernate.query.ResultListTransformer;
|
||||
import org.hibernate.query.TupleTransformer;
|
||||
|
||||
public abstract class QueryOptionsAdapter implements QueryOptions {
|
||||
|
||||
@Override
|
||||
public Limit getLimit() {
|
||||
return Limit.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getFetchSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockOptions getLockOptions() {
|
||||
return LockOptions.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDatabaseHints() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlushMode getFlushMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheRetrieveMode getCacheRetrieveMode() {
|
||||
return CacheRetrieveMode.BYPASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheStoreMode getCacheStoreMode() {
|
||||
return CacheStoreMode.BYPASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheMode getCacheMode() {
|
||||
return CacheMode.IGNORE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isResultCachingEnabled() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultCacheRegionName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppliedGraph getAppliedGraph() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleTransformer getTupleTransformer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultListTransformer getResultListTransformer() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.cache.spi.QueryKey;
|
||||
import org.hibernate.cache.spi.QueryResultsCache;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.loader.ast.spi.AfterLoadAction;
|
||||
import org.hibernate.query.internal.ScrollableResultsIterator;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
@ -78,7 +79,7 @@ public <R> List<R> list(
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
ListResultsConsumer.instance(uniqueFilter)
|
||||
ListResultsConsumer.instance( uniqueFilter )
|
||||
);
|
||||
}
|
||||
|
||||
@ -130,6 +131,37 @@ private <T, R> T executeQuery(
|
||||
RowTransformer<R> rowTransformer,
|
||||
Function<String, PreparedStatement> statementCreator,
|
||||
ResultsConsumer<T, R> resultsConsumer) {
|
||||
final PersistenceContext persistenceContext = executionContext.getSession().getPersistenceContext();
|
||||
boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly();
|
||||
Boolean readOnly = executionContext.getQueryOptions().isReadOnly();
|
||||
if ( readOnly != null ) {
|
||||
// The read-only/modifiable mode for the query was explicitly set.
|
||||
// Temporarily set the default read-only/modifiable setting to the query's setting.
|
||||
persistenceContext.setDefaultReadOnly( readOnly );
|
||||
}
|
||||
try {
|
||||
return doExecuteQuery(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
executionContext,
|
||||
rowTransformer,
|
||||
statementCreator,
|
||||
resultsConsumer
|
||||
);
|
||||
}
|
||||
finally {
|
||||
if ( readOnly != null ) {
|
||||
persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
|
||||
}
|
||||
}
|
||||
}
|
||||
private <T, R> T doExecuteQuery(
|
||||
JdbcSelect jdbcSelect,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
ExecutionContext executionContext,
|
||||
RowTransformer<R> rowTransformer,
|
||||
Function<String, PreparedStatement> statementCreator,
|
||||
ResultsConsumer<T, R> resultsConsumer) {
|
||||
|
||||
final JdbcValues jdbcValues = resolveJdbcValuesSource(
|
||||
jdbcSelect,
|
||||
@ -203,7 +235,6 @@ public boolean shouldReturnProxies() {
|
||||
afterLoadAction.afterLoad( executionContext.getSession(), null, null );
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,80 @@
|
||||
package org.hibernate.orm.test.loading;
|
||||
|
||||
import java.util.Collections;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.jpa.QueryHints;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
ReadonlyHintTest.SimpleEntity.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@TestForIssue( jiraKey = "HHH-11958" )
|
||||
public class ReadonlyHintTest {
|
||||
|
||||
private static final String ORIGINAL_NAME = "original";
|
||||
private static final String CHANGED_NAME = "changed";
|
||||
|
||||
@BeforeEach
|
||||
void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
SimpleEntity entity = new SimpleEntity();
|
||||
entity.id = 1L;
|
||||
entity.name = ORIGINAL_NAME;
|
||||
session.persist( entity );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithReadOnlyHint(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
SimpleEntity fetchedEntity = session.find( SimpleEntity.class, 1L, Collections.singletonMap( QueryHints.HINT_READONLY, true ) );
|
||||
fetchedEntity.name = CHANGED_NAME;
|
||||
} );
|
||||
|
||||
scope.inTransaction( session -> {
|
||||
SimpleEntity fetchedEntity = session.find( SimpleEntity.class, 1L );
|
||||
assertThat(fetchedEntity.name, is( ORIGINAL_NAME ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithoutReadOnlyHint(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
SimpleEntity fetchedEntity = session.find( SimpleEntity.class, 1L );
|
||||
fetchedEntity.name = CHANGED_NAME;
|
||||
} );
|
||||
|
||||
scope.inTransaction( session -> {
|
||||
SimpleEntity fetchedEntity = session.find( SimpleEntity.class, 1L );
|
||||
assertThat(fetchedEntity.name, is( CHANGED_NAME ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> session.createQuery( "delete from SimpleEntity" ).executeUpdate() );
|
||||
}
|
||||
|
||||
@Entity(name = "SimpleEntity")
|
||||
public static class SimpleEntity {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user