Merge remote-tracking branch 'upstream/master' into wip/6.0
This commit is contained in:
commit
005c4cea63
|
@ -329,9 +329,9 @@ test {
|
|||
jvmArgs '-XX:+StartAttachListener'
|
||||
}
|
||||
|
||||
// Enable the experimental features of ByteBuddy with JDK 15+
|
||||
// Enable the experimental features of ByteBuddy with JDK 18+
|
||||
test {
|
||||
if ( gradle.ext.javaVersions.test.release.asInt() >= 15 ) {
|
||||
if ( gradle.ext.javaVersions.test.release.asInt() >= 18 ) {
|
||||
logger.warn( "The version of Java bytecode that will be tested is not supported by Bytebuddy by default. " +
|
||||
" Setting 'net.bytebuddy.experimental=true'." )
|
||||
systemProperty 'net.bytebuddy.experimental', true
|
||||
|
|
|
@ -26,7 +26,7 @@ ext {
|
|||
weldVersion = '3.1.5.Final'
|
||||
|
||||
javassistVersion = '3.27.0-GA'
|
||||
byteBuddyVersion = '1.10.17'
|
||||
byteBuddyVersion = '1.10.21'
|
||||
|
||||
agroalVersion = '1.9'
|
||||
|
||||
|
|
|
@ -6,17 +6,20 @@
|
|||
*/
|
||||
package org.hibernate.bytecode;
|
||||
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BytecodeLogger extends BasicLogger {
|
||||
public interface BytecodeLogging {
|
||||
String NAME = "org.hibernate.orm.bytecode";
|
||||
|
||||
Logger LOGGER = Logger.getLogger( NAME );
|
||||
|
||||
static String subLoggerName(String subName) {
|
||||
return NAME + "." + subName;
|
||||
}
|
||||
|
||||
boolean TRACE_ENABLED = LOGGER.isTraceEnabled();
|
||||
boolean DEBUG_ENABLED = LOGGER.isDebugEnabled();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.bytecode.enhance.spi.interceptor;
|
||||
|
||||
import org.hibernate.bytecode.BytecodeLogging;
|
||||
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.LogMessage;
|
||||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
import org.jboss.logging.annotations.ValidIdRange;
|
||||
|
||||
import static org.jboss.logging.Logger.Level.WARN;
|
||||
|
||||
/**
|
||||
* Logging related to bytecode enhancement interceptors
|
||||
*/
|
||||
@MessageLogger(projectCode = "HHH")
|
||||
@ValidIdRange(min = 90005901, max = 90006000)
|
||||
public interface BytecodeInterceptorLogging extends BasicLogger {
|
||||
String SUB_NAME = "interceptor";
|
||||
String NAME = BytecodeLogging.subLoggerName(SUB_NAME);
|
||||
|
||||
Logger LOGGER = Logger.getLogger(NAME);
|
||||
BytecodeInterceptorLogging MESSAGE_LOGGER = Logger.getMessageLogger(BytecodeInterceptorLogging.class, NAME);
|
||||
|
||||
boolean TRACE_ENABLED = LOGGER.isTraceEnabled();
|
||||
boolean DEBUG_ENABLED = LOGGER.isDebugEnabled();
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
id = 90005901,
|
||||
value = "`%s#%s` was mapped with explicit lazy-group (`%s`). Hibernate will ignore the lazy-group - this is generally " +
|
||||
"not a good idea for to-one associations as it would lead to 2 separate SQL selects to initialize the association. " +
|
||||
"This is expected to be improved in future versions of Hibernate"
|
||||
)
|
||||
void lazyGroupIgnoredForToOne(String ownerName, String attributeName, String requestedLazyGroup);
|
||||
}
|
|
@ -13,7 +13,7 @@ import java.util.Set;
|
|||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.bytecode.BytecodeLogger;
|
||||
import org.hibernate.bytecode.BytecodeLogging;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
|
@ -170,7 +170,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter
|
|||
}
|
||||
|
||||
public Object forceInitialize(Object target, String attributeName) {
|
||||
BytecodeLogger.LOGGER.tracef(
|
||||
BytecodeLogging.LOGGER.tracef(
|
||||
"EnhancementAsProxyLazinessInterceptor#forceInitialize : %s#%s -> %s )",
|
||||
entityKey.getEntityName(),
|
||||
entityKey.getIdentifier(),
|
||||
|
@ -186,7 +186,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter
|
|||
}
|
||||
|
||||
public Object forceInitialize(Object target, String attributeName, SharedSessionContractImplementor session, boolean isTemporarySession) {
|
||||
BytecodeLogger.LOGGER.tracef(
|
||||
BytecodeLogging.LOGGER.tracef(
|
||||
"EnhancementAsProxyLazinessInterceptor#forceInitialize : %s#%s -> %s )",
|
||||
entityKey.getEntityName(),
|
||||
entityKey.getIdentifier(),
|
||||
|
|
|
@ -11,12 +11,11 @@ import java.util.function.BiFunction;
|
|||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.hibernate.bytecode.BytecodeLogger;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.SessionFactoryRegistry;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.OneToOne;
|
||||
import org.hibernate.mapping.ManyToOne;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
|
@ -25,19 +24,26 @@ import org.hibernate.mapping.Value;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnhancementHelper {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface InheritanceChecker {
|
||||
boolean hasSubclasses(String entityName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the given property be included in the owner's base fetch group?
|
||||
*/
|
||||
public static boolean includeInBaseFetchGroup(
|
||||
Property bootMapping,
|
||||
boolean isEnhanced,
|
||||
InheritanceChecker inheritanceChecker,
|
||||
boolean collectionsInDefaultFetchGroupEnabled) {
|
||||
final Value value = bootMapping.getValue();
|
||||
|
||||
if ( ! isEnhanced ) {
|
||||
if ( value instanceof ToOne ) {
|
||||
if ( ( (ToOne) value ).isUnwrapProxy() ) {
|
||||
BytecodeLogger.LOGGER.debugf(
|
||||
BytecodeInterceptorLogging.MESSAGE_LOGGER.debugf(
|
||||
"To-one property `%s#%s` was mapped with LAZY + NO_PROXY but the class was not enhanced",
|
||||
bootMapping.getPersistentClass().getEntityName(),
|
||||
bootMapping.getName()
|
||||
|
@ -47,27 +53,89 @@ public class EnhancementHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
// if we get here, we know the property owner is enhanced for laziness
|
||||
//
|
||||
// NOTE : we make the (potentially untrue) assumption here that
|
||||
// if the owner is enhanced, then all classes are enhanced..
|
||||
|
||||
if ( value instanceof ToOne ) {
|
||||
final ToOne toOne = (ToOne) value;
|
||||
if ( toOne.isLazy() ) {
|
||||
if ( toOne.isUnwrapProxy() ) {
|
||||
if ( toOne instanceof OneToOne ) {
|
||||
return false;
|
||||
}
|
||||
// include it in the base fetch group so long as the config allows
|
||||
// using the FK to create an "enhancement proxy"
|
||||
//return allowEnhancementAsProxy;
|
||||
// ^^ previously we had to explicitly enable use of enhanced proxies.
|
||||
// for the moment just return `true` assuming we can.
|
||||
//
|
||||
// there are cases where this block overall misses quite a few cases
|
||||
// where it returns the least optimal value. This is true even outside
|
||||
// this enhanced-proxy point
|
||||
//
|
||||
// those will all be addressed in the commits for HHH-13658
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! toOne.isLazy() ) {
|
||||
// its not lazy... select it
|
||||
return true;
|
||||
}
|
||||
|
||||
// it is lazy. see if we should select the FK
|
||||
|
||||
if ( bootMapping.getLazyGroup() != null ) {
|
||||
// a non-base fetch group was explicitly specified
|
||||
//
|
||||
// really this should indicate to not select it as part of the base group.
|
||||
// however, at the time being that leads to inefficient SQL - so for now
|
||||
// we simply log a message that we are ignoring the `@LazyGroup` for to-ones
|
||||
|
||||
BytecodeInterceptorLogging.MESSAGE_LOGGER.lazyGroupIgnoredForToOne(
|
||||
bootMapping.getPersistentClass().getEntityName(),
|
||||
bootMapping.getName(),
|
||||
bootMapping.getLazyGroup()
|
||||
);
|
||||
|
||||
// at a later time - for example 6.0 when we can implement the join solution
|
||||
// todo (6.0) : implement this
|
||||
// return false;
|
||||
|
||||
// for now, fall through
|
||||
}
|
||||
|
||||
if ( ! toOne.isReferenceToPrimaryKey() ) {
|
||||
// we do not have a reference to the associated primary-key
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( toOne.getColumnSpan() == 0 ) {
|
||||
// generally this would indicate a "shared PK" on-to-one and there
|
||||
// is no column for the association on the owner table - do not add
|
||||
// the association to the base group (which would force an immediate
|
||||
// select from the association table effectively making this
|
||||
// association non-lazy)
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean unwrapExplicitlyRequested = toOne.isUnwrapProxy() && !toOne.isUnwrapProxyImplicit();
|
||||
|
||||
if ( inheritanceChecker.hasSubclasses( toOne.getReferencedEntityName() ) ) {
|
||||
// the associated type has subclasses - we cannot use the enhanced proxy and will generate a HibernateProxy
|
||||
if ( unwrapExplicitlyRequested ) {
|
||||
// NO_PROXY was explicitly requested
|
||||
BytecodeInterceptorLogging.LOGGER.debugf(
|
||||
"`%s#%s` was mapped with LAZY and explicit NO_PROXY but the associated entity (`%s`) has subclasses",
|
||||
bootMapping.getPersistentClass().getEntityName(),
|
||||
bootMapping.getName(),
|
||||
toOne.getReferencedEntityName()
|
||||
);
|
||||
}
|
||||
// however, select the fk to create the enhanced-proxy
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( toOne instanceof ManyToOne && ( (ManyToOne) toOne ).isIgnoreNotFound() ) {
|
||||
if ( unwrapExplicitlyRequested ) {
|
||||
BytecodeInterceptorLogging.LOGGER.debugf(
|
||||
"%s#%s specified NotFoundAction.IGNORE & LazyToOneOption.NO_PROXY; " +
|
||||
"skipping FK selection to more efficiently handle NotFoundAction.IGNORE",
|
||||
bootMapping.getPersistentClass().getEntityName(),
|
||||
bootMapping.getName()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( unwrapExplicitlyRequested ) {
|
||||
// NO_PROXY was explicitly requested...
|
||||
// - we return true here based on the assumption that `isEnhanced`
|
||||
// is true for all classes - select the FK so we can build the enhanced-proxy
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -118,7 +186,7 @@ public class EnhancementHelper {
|
|||
|
||||
// If we are using a temporary Session, begin a transaction if necessary
|
||||
if ( isTempSession ) {
|
||||
BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork started temporary Session" );
|
||||
BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork started temporary Session" );
|
||||
|
||||
isJta = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
|
||||
|
||||
|
@ -128,7 +196,7 @@ public class EnhancementHelper {
|
|||
// be created even if a current session and transaction are
|
||||
// open (ex: session.clear() was used). We must prevent
|
||||
// multiple transactions.
|
||||
BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork starting transaction on temporary Session" );
|
||||
BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork starting transaction on temporary Session" );
|
||||
session.beginTransaction();
|
||||
}
|
||||
}
|
||||
|
@ -142,12 +210,12 @@ public class EnhancementHelper {
|
|||
try {
|
||||
// Commit the JDBC transaction if we started one.
|
||||
if ( !isJta ) {
|
||||
BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork committing transaction on temporary Session" );
|
||||
BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork committing transaction on temporary Session" );
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
BytecodeLogger.LOGGER.warn(
|
||||
BytecodeInterceptorLogging.LOGGER.warn(
|
||||
"Unable to commit JDBC transaction on temporary session used to load lazy " +
|
||||
"collection associated to no session"
|
||||
);
|
||||
|
@ -155,11 +223,11 @@ public class EnhancementHelper {
|
|||
|
||||
// Close the just opened temp Session
|
||||
try {
|
||||
BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork closing temporary Session" );
|
||||
BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork closing temporary Session" );
|
||||
session.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
BytecodeLogger.LOGGER.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
|
||||
BytecodeInterceptorLogging.LOGGER.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public class LazyAttributeLoadingInterceptor extends AbstractLazyLoadInterceptor
|
|||
}
|
||||
|
||||
public boolean hasAnyUninitializedAttributes() {
|
||||
if ( lazyFields == null ) {
|
||||
if ( lazyFields == null || lazyFields.isEmpty() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
|
||||
/**
|
||||
* Information about all of the bytecode lazy attributes for an entity
|
||||
|
@ -34,7 +36,8 @@ public class LazyAttributesMetadata implements Serializable {
|
|||
public static LazyAttributesMetadata from(
|
||||
PersistentClass mappedEntity,
|
||||
boolean isEnhanced,
|
||||
boolean collectionsInDefaultFetchGroupEnabled) {
|
||||
boolean collectionsInDefaultFetchGroupEnabled,
|
||||
PersisterCreationContext creationContext) {
|
||||
final Map<String, LazyAttributeDescriptor> lazyAttributeDescriptorMap = new LinkedHashMap<>();
|
||||
final Map<String, Set<String>> fetchGroupToAttributesMap = new HashMap<>();
|
||||
|
||||
|
@ -47,6 +50,12 @@ public class LazyAttributesMetadata implements Serializable {
|
|||
final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup(
|
||||
property,
|
||||
isEnhanced,
|
||||
(entityName) -> {
|
||||
final MetadataImplementor metadata = creationContext.getMetadata();
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityName );
|
||||
assert entityBinding != null;
|
||||
return entityBinding.hasSubclasses();
|
||||
},
|
||||
collectionsInDefaultFetchGroupEnabled
|
||||
);
|
||||
if ( lazy ) {
|
||||
|
|
|
@ -3248,7 +3248,8 @@ public final class AnnotationBinder {
|
|||
}
|
||||
else {
|
||||
toOne.setLazy( fetchType == FetchType.LAZY );
|
||||
toOne.setUnwrapProxy( false );
|
||||
toOne.setUnwrapProxy( fetchType != FetchType.LAZY );
|
||||
toOne.setUnwrapProxyImplicit( true );
|
||||
}
|
||||
if ( fetch != null ) {
|
||||
if ( fetch.value() == org.hibernate.annotations.FetchMode.JOIN ) {
|
||||
|
|
|
@ -39,6 +39,26 @@ public enum OptimisticLockStyle {
|
|||
return oldCode;
|
||||
}
|
||||
|
||||
public boolean isAllOrDirty() {
|
||||
return isAll() || isDirty();
|
||||
}
|
||||
|
||||
public boolean isAll() {
|
||||
return this == ALL;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return this == DIRTY;
|
||||
}
|
||||
|
||||
public boolean isVersion() {
|
||||
return this == VERSION;
|
||||
}
|
||||
|
||||
public boolean isNone() {
|
||||
return this == NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an old code (one of the int constants from Cascade), interpret it as one of the new enums.
|
||||
*
|
||||
|
|
|
@ -13,6 +13,9 @@ import org.hibernate.CacheMode;
|
|||
import org.hibernate.IdentifierLoadAccess;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.ObjectNotFoundException;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
|
@ -22,6 +25,8 @@ import org.hibernate.graph.GraphSemantic;
|
|||
import org.hibernate.graph.RootGraph;
|
||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -152,7 +157,10 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
|
|||
if ( this.lockOptions != null ) {
|
||||
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, eventSource, loadQueryInfluencers.getReadOnly() );
|
||||
context.fireLoad( event, LoadEventListener.GET );
|
||||
return (T) event.getResult();
|
||||
final Object result = event.getResult();
|
||||
initializeIfNecessary( result );
|
||||
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, eventSource, loadQueryInfluencers.getReadOnly() );
|
||||
|
@ -167,6 +175,35 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> {
|
|||
finally {
|
||||
context.afterOperation( success );
|
||||
}
|
||||
return (T) event.getResult();
|
||||
|
||||
final Object result = event.getResult();
|
||||
initializeIfNecessary( result );
|
||||
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
private void initializeIfNecessary(Object result) {
|
||||
if ( result == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( result instanceof HibernateProxy ) {
|
||||
final HibernateProxy hibernateProxy = (HibernateProxy) result;
|
||||
final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
|
||||
if ( initializer.isUninitialized() ) {
|
||||
initializer.initialize();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final BytecodeEnhancementMetadata enhancementMetadata = entityPersister.getEntityMetamodel().getBytecodeEnhancementMetadata();
|
||||
if ( ! enhancementMetadata.isEnhancedForLazyLoading() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BytecodeLazyAttributeInterceptor interceptor = enhancementMetadata.extractLazyInterceptor( result);
|
||||
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
|
||||
( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( result, null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public abstract class ToOne extends SimpleValue implements Fetchable {
|
|||
private String propertyName;
|
||||
private boolean lazy = true;
|
||||
protected boolean unwrapProxy;
|
||||
protected boolean isUnwrapProxyImplicit;
|
||||
protected boolean referenceToPrimaryKey = true;
|
||||
|
||||
protected ToOne(MetadataBuildingContext buildingContext, Table table) {
|
||||
|
@ -123,6 +124,18 @@ public abstract class ToOne extends SimpleValue implements Fetchable {
|
|||
this.unwrapProxy = unwrapProxy;
|
||||
}
|
||||
|
||||
public boolean isUnwrapProxyImplicit() {
|
||||
return isUnwrapProxyImplicit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Related to HHH-13658 - keep track of whether `unwrapProxy` is an implicit value
|
||||
* for reference later
|
||||
*/
|
||||
public void setUnwrapProxyImplicit(boolean unwrapProxyImplicit) {
|
||||
isUnwrapProxyImplicit = unwrapProxyImplicit;
|
||||
}
|
||||
|
||||
public boolean isReferenceToPrimaryKey() {
|
||||
return referenceToPrimaryKey;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
|
@ -219,7 +220,6 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
|
|||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.FetchableContainer;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
|
@ -705,7 +705,7 @@ public abstract class AbstractEntityPersister
|
|||
this.naturalIdRegionAccessStrategy = null;
|
||||
}
|
||||
|
||||
this.entityMetamodel = new EntityMetamodel( bootDescriptor, this, factory );
|
||||
this.entityMetamodel = new EntityMetamodel( bootDescriptor, this, creationContext );
|
||||
|
||||
if ( entityMetamodel.isMutable() ) {
|
||||
this.entityEntryFactory = MutableEntityEntryFactory.INSTANCE;
|
||||
|
@ -867,6 +867,12 @@ public abstract class AbstractEntityPersister
|
|||
final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup(
|
||||
prop,
|
||||
entityMetamodel.isInstrumented(),
|
||||
(entityName) -> {
|
||||
final MetadataImplementor metadata = creationContext.getMetadata();
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityName );
|
||||
assert entityBinding != null;
|
||||
return entityBinding.hasSubclasses();
|
||||
},
|
||||
sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled()
|
||||
);
|
||||
|
||||
|
@ -946,6 +952,12 @@ public abstract class AbstractEntityPersister
|
|||
final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup(
|
||||
prop,
|
||||
entityMetamodel.isInstrumented(),
|
||||
(entityName) -> {
|
||||
final MetadataImplementor metadata = creationContext.getMetadata();
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityName );
|
||||
assert entityBinding != null;
|
||||
return entityBinding.hasSubclasses();
|
||||
},
|
||||
sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled()
|
||||
);
|
||||
while ( colIter.hasNext() ) {
|
||||
|
@ -1795,8 +1807,8 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
public boolean isBatchable() {
|
||||
return optimisticLockStyle() == OptimisticLockStyle.NONE
|
||||
|| ( !isVersioned() && optimisticLockStyle() == OptimisticLockStyle.VERSION )
|
||||
return optimisticLockStyle().isNone()
|
||||
|| !isVersioned() && optimisticLockStyle().isVersion()
|
||||
|| getFactory().getSessionFactoryOptions().isJdbcBatchVersionedData();
|
||||
}
|
||||
|
||||
|
@ -2011,14 +2023,13 @@ public abstract class AbstractEntityPersister
|
|||
// rather than trying to handle the individual generated portions.
|
||||
String selectClause = concretePropertySelectFragment(
|
||||
getRootAlias(),
|
||||
new InclusionChecker() {
|
||||
@Override
|
||||
public boolean includeProperty(int propertyNumber) {
|
||||
final InDatabaseValueGenerationStrategy generationStrategy
|
||||
= entityMetamodel.getInDatabaseValueGenerationStrategies()[propertyNumber];
|
||||
return generationStrategy != null
|
||||
&& timingsMatch( generationStrategy.getGenerationTiming(), generationTimingToMatch );
|
||||
}
|
||||
propertyNumber -> {
|
||||
final InDatabaseValueGenerationStrategy generationStrategy
|
||||
= entityMetamodel.getInDatabaseValueGenerationStrategies()[propertyNumber];
|
||||
GenerationTiming timing = generationStrategy.getGenerationTiming();
|
||||
return generationStrategy != null
|
||||
&& (generationTimingToMatch == GenerationTiming.INSERT && timing.includesInsert()
|
||||
|| generationTimingToMatch == GenerationTiming.ALWAYS && timing.includesUpdate());
|
||||
}
|
||||
);
|
||||
selectClause = selectClause.substring( 2 );
|
||||
|
@ -2046,11 +2057,7 @@ public abstract class AbstractEntityPersister
|
|||
protected String concretePropertySelectFragment(String alias, final boolean[] includeProperty) {
|
||||
return concretePropertySelectFragment(
|
||||
alias,
|
||||
new InclusionChecker() {
|
||||
public boolean includeProperty(int propertyNumber) {
|
||||
return includeProperty[propertyNumber];
|
||||
}
|
||||
}
|
||||
propertyNumber -> includeProperty[propertyNumber]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2922,7 +2929,7 @@ public abstract class AbstractEntityPersister
|
|||
update.addPrimaryKeyColumns( getKeyColumns( j ) );
|
||||
}
|
||||
|
||||
if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) {
|
||||
if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockStyle().isVersion() ) {
|
||||
// this is the root (versioned) table, and we are using version-based
|
||||
// optimistic locking; if we are not updating the version, also don't
|
||||
// check it (unless this is a "generated" version column)!
|
||||
|
@ -2934,12 +2941,11 @@ public abstract class AbstractEntityPersister
|
|||
else if ( isAllOrDirtyOptLocking() && oldFields != null ) {
|
||||
// we are using "all" or "dirty" property-based optimistic locking
|
||||
|
||||
boolean[] includeInWhere = entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL
|
||||
?
|
||||
getPropertyUpdateability()
|
||||
boolean[] includeInWhere = entityMetamodel.getOptimisticLockStyle().isAll()
|
||||
//optimistic-lock="all", include all updatable properties
|
||||
:
|
||||
includeProperty; //optimistic-lock="dirty", include all properties we are updating this time
|
||||
? getPropertyUpdateability()
|
||||
//optimistic-lock="dirty", include all properties we are updating this time
|
||||
: includeProperty;
|
||||
|
||||
boolean[] versionability = getPropertyVersionability();
|
||||
Type[] types = getPropertyTypes();
|
||||
|
@ -3666,14 +3672,14 @@ public abstract class AbstractEntityPersister
|
|||
);
|
||||
|
||||
// Write any appropriate versioning conditional parameters
|
||||
if ( useVersion && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) {
|
||||
if ( useVersion && entityMetamodel.getOptimisticLockStyle().isVersion()) {
|
||||
if ( checkVersion( includeProperty ) ) {
|
||||
getVersionType().nullSafeSet( update, oldVersion, index, session );
|
||||
}
|
||||
}
|
||||
else if ( isAllOrDirtyOptLocking() && oldFields != null ) {
|
||||
boolean[] versionability = getPropertyVersionability(); //TODO: is this really necessary????
|
||||
boolean[] includeOldField = entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL
|
||||
boolean[] includeOldField = entityMetamodel.getOptimisticLockStyle().isAll()
|
||||
? getPropertyUpdateability()
|
||||
: includeProperty;
|
||||
Type[] types = getPropertyTypes();
|
||||
|
@ -4089,11 +4095,10 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
protected boolean isAllOrDirtyOptLocking() {
|
||||
return entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.DIRTY
|
||||
|| entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL;
|
||||
return entityMetamodel.getOptimisticLockStyle().isAllOrDirty();
|
||||
}
|
||||
|
||||
private String[] generateSQLDeleteStrings(Object[] loadedState) {
|
||||
protected String[] generateSQLDeleteStrings(Object[] loadedState) {
|
||||
int span = getTableSpan();
|
||||
String[] deleteStrings = new String[span];
|
||||
for ( int j = span - 1; j >= 0; j-- ) {
|
||||
|
@ -4664,7 +4669,7 @@ public abstract class AbstractEntityPersister
|
|||
return null;
|
||||
}
|
||||
else if ( interceptor.isAttributeLoaded( nameOfAttributeBeingAccessed ) ) {
|
||||
value = getEntityTuplizer().getPropertyValue( entity, nameOfAttributeBeingAccessed );
|
||||
value = getPropertyValue( entity, nameOfAttributeBeingAccessed );
|
||||
}
|
||||
else {
|
||||
value = ( (LazyPropertyInitializer) this ).initializeLazyProperty( nameOfAttributeBeingAccessed, entity, session );
|
||||
|
@ -5648,12 +5653,11 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
}
|
||||
|
||||
private boolean isValueGenerationRequired(NonIdentifierAttribute attribute, GenerationTiming matchTiming) {
|
||||
if ( attribute.getType() instanceof ComponentType ) {
|
||||
public static boolean isValueGenerationRequired(NonIdentifierAttribute attribute, GenerationTiming matchTiming) {
|
||||
if ( attribute.getType() instanceof ComponentType) {
|
||||
final ComponentType type = (ComponentType) attribute.getType();
|
||||
final ValueGeneration[] propertyValueGenerationStrategies = type.getPropertyValueGenerationStrategies();
|
||||
for ( ValueGeneration propertyValueGenerationStrategie : propertyValueGenerationStrategies ) {
|
||||
if ( isReadRequired( propertyValueGenerationStrategie, matchTiming ) ) {
|
||||
for ( ValueGeneration valueGenerationStrategy : type.getPropertyValueGenerationStrategies() ) {
|
||||
if ( isReadRequired( valueGenerationStrategy, matchTiming ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -5667,16 +5671,10 @@ public abstract class AbstractEntityPersister
|
|||
/**
|
||||
* Whether the given value generation strategy requires to read the value from the database or not.
|
||||
*/
|
||||
private boolean isReadRequired(ValueGeneration valueGeneration, GenerationTiming matchTiming) {
|
||||
return valueGeneration != null &&
|
||||
valueGeneration.getValueGenerator() == null &&
|
||||
timingsMatch( valueGeneration.getGenerationTiming(), matchTiming );
|
||||
}
|
||||
|
||||
private boolean timingsMatch(GenerationTiming timing, GenerationTiming matchTiming) {
|
||||
return
|
||||
( matchTiming == GenerationTiming.INSERT && timing.includesInsert() ) ||
|
||||
( matchTiming == GenerationTiming.ALWAYS && timing.includesUpdate() );
|
||||
private static boolean isReadRequired(ValueGeneration valueGeneration, GenerationTiming matchTiming) {
|
||||
return valueGeneration != null
|
||||
&& valueGeneration.getValueGenerator() == null
|
||||
&& valueGeneration.timingMatches( matchTiming );
|
||||
}
|
||||
|
||||
public String getIdentifierPropertyName() {
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
|
||||
import org.hibernate.engine.OptimisticLockStyle;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -240,7 +239,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
discriminatorSQLString = null;
|
||||
}
|
||||
|
||||
if ( optimisticLockStyle() == OptimisticLockStyle.ALL || optimisticLockStyle() == OptimisticLockStyle.DIRTY ) {
|
||||
if ( optimisticLockStyle().isAllOrDirty() ) {
|
||||
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.reflect.Constructor;
|
|||
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
|
||||
import org.hibernate.engine.internal.UnsavedValueFactory;
|
||||
|
@ -22,6 +23,7 @@ import org.hibernate.mapping.KeyValue;
|
|||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
||||
|
@ -155,7 +157,8 @@ public final class PropertyFactory {
|
|||
SessionFactoryImplementor sessionFactory,
|
||||
int attributeNumber,
|
||||
Property property,
|
||||
boolean lazyAvailable) {
|
||||
boolean lazyAvailable,
|
||||
PersisterCreationContext creationContext) {
|
||||
final Type type = property.getValue().getType();
|
||||
|
||||
final NonIdentifierAttributeNature nature = decode( type );
|
||||
|
@ -174,6 +177,12 @@ public final class PropertyFactory {
|
|||
final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup(
|
||||
property,
|
||||
lazyAvailable,
|
||||
(entityName) -> {
|
||||
final MetadataImplementor metadata = creationContext.getMetadata();
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityName );
|
||||
assert entityBinding != null;
|
||||
return entityBinding.hasSubclasses();
|
||||
},
|
||||
sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled()
|
||||
);
|
||||
|
||||
|
|
|
@ -53,4 +53,13 @@ public interface ValueGeneration extends Serializable {
|
|||
* @return The column value to be used in the SQL.
|
||||
*/
|
||||
public String getDatabaseGeneratedReferencedColumnValue();
|
||||
|
||||
/**
|
||||
* Does this value generation occur with the given timing?
|
||||
*/
|
||||
default boolean timingMatches(GenerationTiming timing) {
|
||||
GenerationTiming generationTiming = getGenerationTiming();
|
||||
return timing == GenerationTiming.INSERT && generationTiming.includesInsert()
|
||||
|| timing == GenerationTiming.ALWAYS && generationTiming.includesUpdate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
/**
|
||||
|
@ -38,11 +39,12 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc
|
|||
PersistentClass persistentClass,
|
||||
Set<String> identifierAttributeNames,
|
||||
CompositeType nonAggregatedCidMapper,
|
||||
boolean collectionsInDefaultFetchGroupEnabled) {
|
||||
boolean collectionsInDefaultFetchGroupEnabled,
|
||||
PersisterCreationContext creationContext) {
|
||||
final Class mappedClass = persistentClass.getMappedClass();
|
||||
final boolean enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( mappedClass );
|
||||
final LazyAttributesMetadata lazyAttributesMetadata = enhancedForLazyLoading
|
||||
? LazyAttributesMetadata.from( persistentClass, true, collectionsInDefaultFetchGroupEnabled )
|
||||
? LazyAttributesMetadata.from( persistentClass, true, collectionsInDefaultFetchGroupEnabled, creationContext )
|
||||
: LazyAttributesMetadata.nonEnhanced( persistentClass.getEntityName() );
|
||||
|
||||
return new BytecodeEnhancementMetadataPojoImpl(
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Set;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
|
@ -35,6 +36,7 @@ import org.hibernate.mapping.Component;
|
|||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.IdentifierProperty;
|
||||
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
|
||||
|
@ -129,8 +131,8 @@ public class EntityMetamodel implements Serializable {
|
|||
public EntityMetamodel(
|
||||
PersistentClass persistentClass,
|
||||
EntityPersister persister,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
PersisterCreationContext creationContext) {
|
||||
this.sessionFactory = creationContext.getSessionFactory();
|
||||
|
||||
name = persistentClass.getEntityName();
|
||||
rootName = persistentClass.getRootClass().getEntityName();
|
||||
|
@ -167,7 +169,8 @@ public class EntityMetamodel implements Serializable {
|
|||
persistentClass,
|
||||
idAttributeNames,
|
||||
nonAggregatedCidMapper,
|
||||
sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled()
|
||||
sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled(),
|
||||
creationContext
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -230,7 +233,8 @@ public class EntityMetamodel implements Serializable {
|
|||
sessionFactory,
|
||||
i,
|
||||
prop,
|
||||
bytecodeEnhancementMetadata.isEnhancedForLazyLoading()
|
||||
bytecodeEnhancementMetadata.isEnhancedForLazyLoading(),
|
||||
creationContext
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -249,6 +253,12 @@ public class EntityMetamodel implements Serializable {
|
|||
boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup(
|
||||
prop,
|
||||
bytecodeEnhancementMetadata.isEnhancedForLazyLoading(),
|
||||
(entityName) -> {
|
||||
final MetadataImplementor metadata = creationContext.getMetadata();
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( entityName );
|
||||
assert entityBinding != null;
|
||||
return entityBinding.hasSubclasses();
|
||||
},
|
||||
sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled()
|
||||
);
|
||||
|
||||
|
@ -383,9 +393,7 @@ public class EntityMetamodel implements Serializable {
|
|||
hasSubclasses = persistentClass.hasSubclasses();
|
||||
|
||||
optimisticLockStyle = persistentClass.getOptimisticLockStyle();
|
||||
final boolean isAllOrDirty =
|
||||
optimisticLockStyle == OptimisticLockStyle.ALL
|
||||
|| optimisticLockStyle == OptimisticLockStyle.DIRTY;
|
||||
final boolean isAllOrDirty = optimisticLockStyle.isAllOrDirty();
|
||||
if ( isAllOrDirty && !dynamicUpdate ) {
|
||||
throw new MappingException( "optimistic-lock=all|dirty requires dynamic-update=\"true\": " + name );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests related to {@link org.hibernate.annotations.LazyToOne}, especially
|
||||
* regarding handling of {@link org.hibernate.annotations.LazyToOneOption#NO_PROXY}
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.lazytoone;
|
|
@ -21,19 +21,26 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil2.fromTransaction;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -42,6 +49,7 @@ import static org.junit.Assert.assertTrue;
|
|||
@TestForIssue(jiraKey = "HHH-10252")
|
||||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlInterceptor;
|
||||
private Child originalChild;
|
||||
|
||||
@Override
|
||||
|
@ -49,6 +57,12 @@ public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
|||
return new Class[] { Parent.class, Child.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
sqlInterceptor = new SQLStatementInterceptor( configuration );
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
// Create a Parent with one Child
|
||||
|
@ -64,46 +78,28 @@ public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testManagedWithUninitializedAssociation() {
|
||||
// Delete the Child
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
Child loadedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" )
|
||||
.setParameter( "name", "CHILD" )
|
||||
.uniqueResult();
|
||||
checkInterceptor( loadedChild, false );
|
||||
assertFalse( Hibernate.isPropertyInitialized( loadedChild, "parent" ) );
|
||||
s.delete( loadedChild );
|
||||
}
|
||||
);
|
||||
// Explicitly check that both got deleted
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManagedWithInitializedAssociation() {
|
||||
sqlInterceptor.clear();
|
||||
|
||||
// Delete the Child
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
Child loadedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" )
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
final Child managedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" )
|
||||
.setParameter( "name", "CHILD" )
|
||||
.uniqueResult();
|
||||
checkInterceptor( loadedChild, false );
|
||||
loadedChild.getParent();
|
||||
assertTrue( Hibernate.isPropertyInitialized( loadedChild, "parent" ) );
|
||||
s.delete( loadedChild );
|
||||
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
// parent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( managedChild, "parent" ) );
|
||||
assertThat( managedChild.getParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( managedChild.getParent() ) );
|
||||
|
||||
s.delete( managedChild );
|
||||
}
|
||||
);
|
||||
|
||||
// Explicitly check that both got deleted
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
|
@ -114,49 +110,21 @@ public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testDetachedWithUninitializedAssociation() {
|
||||
final Child detachedChild = doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
return s.get( Child.class, originalChild.getId() );
|
||||
}
|
||||
);
|
||||
|
||||
assertFalse( Hibernate.isPropertyInitialized( detachedChild, "parent" ) );
|
||||
|
||||
checkInterceptor( detachedChild, false );
|
||||
|
||||
// Delete the detached Child with uninitialized parent
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
s.delete( detachedChild );
|
||||
}
|
||||
);
|
||||
// Explicitly check that both got deleted
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testDetachedWithInitializedAssociation() {
|
||||
final Child detachedChild = doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
Child child = s.get( Child.class, originalChild.getId() );
|
||||
assertFalse( Hibernate.isPropertyInitialized( child, "parent" ) );
|
||||
sqlInterceptor.clear();
|
||||
|
||||
final Child detachedChild = fromTransaction(
|
||||
sessionFactory(),
|
||||
(s) -> {
|
||||
Child child = s.get( Child.class, originalChild.getId() );
|
||||
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
// parent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( child, "parent" ) );
|
||||
assertThat( child.getParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( child.getParent() ) );
|
||||
|
||||
// initialize parent before detaching
|
||||
child.getParent();
|
||||
return child;
|
||||
}
|
||||
);
|
||||
|
@ -166,14 +134,13 @@ public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
|||
checkInterceptor( detachedChild, false );
|
||||
|
||||
// Delete the detached Child with initialized parent
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
s.delete( detachedChild );
|
||||
}
|
||||
inTransaction(
|
||||
(s) -> s.delete( detachedChild )
|
||||
);
|
||||
|
||||
// Explicitly check that both got deleted
|
||||
doInHibernate(
|
||||
this::sessionFactory, s -> {
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||
}
|
||||
|
@ -204,8 +171,7 @@ public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
private void checkInterceptor(Child child, boolean isNullExpected) {
|
||||
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata =
|
||||
sessionFactory()
|
||||
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = sessionFactory()
|
||||
.getMetamodel()
|
||||
.entityPersister( Child.class )
|
||||
.getEntityMetamodel()
|
||||
|
|
|
@ -18,18 +18,23 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -39,81 +44,97 @@ import static org.junit.Assert.assertTrue;
|
|||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
@TestForIssue(jiraKey = "HHH-13129")
|
||||
public class CascadeOnUninitializedTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlInterceptor;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class,
|
||||
Address.class,
|
||||
};
|
||||
return new Class<?>[] { Person.class, Address.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
settings.put( AvailableSettings.SHOW_SQL, "true" );
|
||||
settings.put( AvailableSettings.FORMAT_SQL, "true" );
|
||||
sqlInterceptor = new SQLStatementInterceptor( settings );
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testMergeDetachedEnhancedEntityWithUninitializedManyToOne() {
|
||||
final Person person = persistPersonWithManyToOne();
|
||||
|
||||
Person person = persistPersonWithManyToOne();
|
||||
sqlInterceptor.clear();
|
||||
|
||||
// get a detached Person
|
||||
Person detachedPerson = TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
return session.get( Person.class, person.getId() );
|
||||
}
|
||||
final Person detachedPerson = fromTransaction(
|
||||
session -> session.get( Person.class, person.getId() )
|
||||
);
|
||||
|
||||
// address should not be initialized
|
||||
assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||
// loading Person should lead to one SQL
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
// primaryAddress should be "initialized" as an enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||
assertThat( detachedPerson.getPrimaryAddress(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( detachedPerson.getPrimaryAddress() ) );
|
||||
|
||||
// alter the detached reference
|
||||
detachedPerson.setName( "newName" );
|
||||
|
||||
Person mergedPerson = TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
return (Person) session.merge( detachedPerson );
|
||||
}
|
||||
final Person mergedPerson = fromTransaction(
|
||||
session -> (Person) session.merge( detachedPerson )
|
||||
);
|
||||
|
||||
// address should not be initialized
|
||||
assertFalse( Hibernate.isPropertyInitialized( mergedPerson, "primaryAddress" ) );
|
||||
// 1) select Person#addresses
|
||||
// 2) select Person#primaryAddress
|
||||
// 3) update Person
|
||||
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 3 ) );
|
||||
|
||||
// primaryAddress should not be initialized
|
||||
assertTrue( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||
assertThat( detachedPerson.getPrimaryAddress(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( detachedPerson.getPrimaryAddress() ) );
|
||||
|
||||
assertEquals( "newName", mergedPerson.getName() );
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testDeleteEnhancedEntityWithUninitializedManyToOne() {
|
||||
Person person = persistPersonWithManyToOne();
|
||||
|
||||
sqlInterceptor.clear();
|
||||
|
||||
// get a detached Person
|
||||
Person detachedPerson = TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
return session.get( Person.class, person.getId() );
|
||||
}
|
||||
Person detachedPerson = fromTransaction(
|
||||
session -> session.get( Person.class, person.getId() )
|
||||
);
|
||||
|
||||
// address should not be initialized
|
||||
assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||
// loading Person should lead to one SQL
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
// deleting detachedPerson should result in detachedPerson.address being initialized,
|
||||
// primaryAddress should be initialized as an enhance-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||
assertThat( detachedPerson, not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( detachedPerson.getPrimaryAddress() ) );
|
||||
|
||||
sqlInterceptor.clear();
|
||||
|
||||
// deleting detachedPerson should result in detachedPerson.primaryAddress being initialized,
|
||||
// so that the DELETE operation can be cascaded to it.
|
||||
TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
session.delete( detachedPerson );
|
||||
}
|
||||
inTransaction(
|
||||
session -> session.delete( detachedPerson )
|
||||
);
|
||||
|
||||
// 1) select Person#addresses
|
||||
// 2) select Person#primaryAddress
|
||||
// 3) delete Person
|
||||
// 4) select primary Address
|
||||
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 4 ) );
|
||||
|
||||
// both the Person and its Address should be deleted
|
||||
TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
session -> {
|
||||
assertNull( session.get( Person.class, person.getId() ) );
|
||||
assertNull( session.get( Person.class, person.getPrimaryAddress().getId() ) );
|
||||
}
|
||||
|
@ -223,12 +244,12 @@ public class CascadeOnUninitializedTest extends BaseNonConfigCoreFunctionalTestC
|
|||
private String name;
|
||||
|
||||
@ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "ADDRESS_ID")
|
||||
@JoinColumn(name = "primary_address_id")
|
||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||
private Address primaryAddress;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
@JoinColumn
|
||||
@JoinColumn( name = "person_id" )
|
||||
private Set<Address> addresses = new HashSet<>();
|
||||
|
||||
public Long getId() {
|
||||
|
|
|
@ -20,13 +20,14 @@ import org.hibernate.Session;
|
|||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
|
@ -35,7 +36,10 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -54,21 +58,26 @@ import static org.junit.Assert.assertTrue;
|
|||
EnhancerTestContext.class, // supports laziness and dirty-checking
|
||||
BidirectionalLazyTest.NoDirtyCheckEnhancementContext.class // supports laziness; does not support dirty-checking
|
||||
})
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
// NOTE : tests in this class seem redundant because they assert things that happened
|
||||
// in previous versions that have been fixed
|
||||
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Employer.class, Employee.class, Unrelated.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveWithDeletedAssociatedEntity() {
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
|
||||
Employer employer = new Employer( "RedHat" );
|
||||
session.persist( employer );
|
||||
|
@ -81,27 +90,27 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
Employer employer = session.get( Employer.class, "RedHat" );
|
||||
|
||||
// Delete the associated entity first
|
||||
session.remove( employer );
|
||||
|
||||
for ( Employee employee : employer.getEmployees() ) {
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
session.remove( employee );
|
||||
// Should be initialized because at least one entity was deleted beforehand
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
session.remove( employee );
|
||||
|
||||
assertSame( employer, employee.getEmployer() );
|
||||
|
||||
// employee.getEmployer was initialized, and should be nullified in EntityEntry#deletedState
|
||||
checkEntityEntryState( session, employee, employer, true );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
assertNull( session.find( Employer.class, "RedHat" ) );
|
||||
assertTrue( session.createQuery( "from Employee e", Employee.class ).getResultList().isEmpty() );
|
||||
}
|
||||
|
@ -111,8 +120,8 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
@Test
|
||||
public void testRemoveWithNonAssociatedRemovedEntity() {
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
Employer employer = new Employer( "RedHat" );
|
||||
session.persist( employer );
|
||||
Employee employee = new Employee( "Jack" );
|
||||
|
@ -122,22 +131,22 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
// Delete an entity that is not associated with Employee
|
||||
session.remove( session.get( Unrelated.class, 1 ) );
|
||||
final Employee employee = session.get( Employee.class, "Jack" );
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
session.remove( employee );
|
||||
// Should be initialized because at least one entity was deleted beforehand
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
|
||||
session.remove( employee );
|
||||
|
||||
// employee.getEmployer was initialized, and should not be nullified in EntityEntry#deletedState
|
||||
checkEntityEntryState( session, employee, employee.getEmployer(), false );
|
||||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
assertNull( session.find( Unrelated.class, 1 ) );
|
||||
assertNull( session.find( Employee.class, "Jack" ) );
|
||||
session.remove( session.find( Employer.class, "RedHat" ) );
|
||||
|
@ -148,8 +157,8 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
@Test
|
||||
public void testRemoveWithNoRemovedEntities() {
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
Employer employer = new Employer( "RedHat" );
|
||||
session.persist( employer );
|
||||
Employee employee = new Employee( "Jack" );
|
||||
|
@ -158,22 +167,25 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
// Don't delete any entities before deleting the Employee
|
||||
final Employee employee = session.get( Employee.class, "Jack" );
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
verifyBaseState( employee );
|
||||
|
||||
session.remove( employee );
|
||||
// There were no other deleted entities before employee was deleted,
|
||||
// so there was no need to initialize employee.employer.
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
// employee.getEmployer was not initialized, and should not be nullified in EntityEntry#deletedState
|
||||
checkEntityEntryState( session, employee, LazyPropertyInitializer.UNFETCHED_PROPERTY, false );
|
||||
|
||||
Employer employer = session.get( Employer.class, "RedHat" );
|
||||
verifyBaseState( employer );
|
||||
|
||||
assertThat( employee.getEmployer(), sameInstance( employer ) );
|
||||
|
||||
checkEntityEntryState( session, employee, employer, false );
|
||||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
assertNull( session.find( Employee.class, "Jack" ) );
|
||||
session.remove( session.find( Employer.class, "RedHat" ) );
|
||||
}
|
||||
|
@ -183,8 +195,8 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
@Test
|
||||
public void testRemoveEntityWithNullLazyManyToOne() {
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
Employer employer = new Employer( "RedHat" );
|
||||
session.persist( employer );
|
||||
Employee employee = new Employee( "Jack" );
|
||||
|
@ -192,22 +204,17 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
Employee employee = session.get( Employee.class, "Jack" );
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
verifyBaseState( employee );
|
||||
|
||||
// Get and delete an Employer that is not associated with employee
|
||||
Employer employer = session.get( Employer.class, "RedHat" );
|
||||
session.remove( employer );
|
||||
verifyBaseState( employer );
|
||||
|
||||
// employee.employer is uninitialized. Since the column for employee.employer
|
||||
// is a foreign key, and there is an Employer that has already been removed,
|
||||
// employee.employer will need to be iniitialized to determine if
|
||||
// employee.employer is nullifiable.
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
session.remove( employer );
|
||||
session.remove( employee );
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -231,23 +238,37 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
inTransaction(
|
||||
session -> {
|
||||
Employee employee = session.get( Employee.class, "Jack" );
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
verifyBaseState( employee );
|
||||
|
||||
// Get and delete an Employer that is not associated with employee
|
||||
Employer employer = session.get( Employer.class, "RedHat" );
|
||||
session.remove( employer );
|
||||
verifyBaseState( employer );
|
||||
|
||||
// employee.employer is uninitialized. Since the column for employee.employer
|
||||
// is a foreign key, and there is an Employer that has already been removed,
|
||||
// employee.employer will need to be iniitialized to determine if
|
||||
// employee.employer is nullifiable.
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
assertThat( employee.getEmployer(), sameInstance( employer ) );
|
||||
|
||||
session.remove( employer );
|
||||
session.remove( employee );
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void verifyBaseState(Employer employer) {
|
||||
assertTrue( Hibernate.isPropertyInitialized( employer, "name" ) );
|
||||
}
|
||||
|
||||
private void verifyBaseState(Employee employee) {
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "name" ) );
|
||||
|
||||
// employer will be either null or an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
|
||||
final Employer employer = employee.getEmployer();
|
||||
if ( employer != null ) {
|
||||
assertFalse( Hibernate.isInitialized( employer ) );
|
||||
assertThat(employer, not( instanceOf( HibernateProxy.class ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEntityEntryState(
|
||||
final Session session,
|
||||
final Employee employee,
|
||||
|
@ -261,7 +282,7 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
entityEntry.getLoadedState()[propertyNumber]
|
||||
);
|
||||
if ( isEmployerNullified ) {
|
||||
assertEquals( null, entityEntry.getDeletedState()[propertyNumber] );
|
||||
assertNull( entityEntry.getDeletedState()[ propertyNumber ] );
|
||||
}
|
||||
else {
|
||||
assertEquals(
|
||||
|
@ -372,7 +393,7 @@ public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase {
|
|||
return true;
|
||||
}
|
||||
else if ( o instanceof Employee ) {
|
||||
Employee other = Employee.class.cast( o );
|
||||
Employee other = (Employee) o;
|
||||
if ( name != null ) {
|
||||
return getName().equals( other.getName() );
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.hibernate.boot.SessionFactoryBuilder;
|
|||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
|
@ -33,6 +32,8 @@ import org.junit.runner.RunWith;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
|
@ -44,36 +45,39 @@ import static org.junit.Assert.assertFalse;
|
|||
public class NaturalIdInUninitializedAssociationTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testImmutableNaturalId() {
|
||||
public void testLoad() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
final AnEntity e = session.get( AnEntity.class, 3 );
|
||||
assertFalse( Hibernate.isPropertyInitialized( e,"entityImmutableNaturalId" ) );
|
||||
}
|
||||
);
|
||||
final AnEntity e = session.byId( AnEntity.class ).load(3 );
|
||||
assertTrue( Hibernate.isInitialized( e ) );
|
||||
|
||||
inTransaction(
|
||||
session -> {
|
||||
final AnEntity e = session.get( AnEntity.class, 3 );
|
||||
// because we can (enhanced) proxy both EntityMutableNaturalId and EntityImmutableNaturalId
|
||||
// we will select their FKs and all attributes will be "bytecode initialized"
|
||||
assertTrue( Hibernate.isPropertyInitialized( e,"entityMutableNaturalId" ) );
|
||||
assertTrue( Hibernate.isPropertyInitialized( e,"entityImmutableNaturalId" ) );
|
||||
|
||||
assertEquals( "mutable name", e.entityMutableNaturalId.name );
|
||||
assertEquals( "immutable name", e.entityImmutableNaturalId.name );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void testMutableNaturalId() {
|
||||
public void testGetReference() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
final AnEntity e = session.get( AnEntity.class, 3 );
|
||||
assertFalse( Hibernate.isPropertyInitialized( e,"entityMutableNaturalId" ) );
|
||||
final AnEntity e = session.byId( AnEntity.class ).getReference( 3 );
|
||||
assertFalse( Hibernate.isInitialized( e ) );
|
||||
|
||||
// trigger initialization
|
||||
Hibernate.initialize( e );
|
||||
// silly, but...
|
||||
assertTrue( Hibernate.isInitialized( e ) );
|
||||
|
||||
// because we can (enhanced) proxy both EntityMutableNaturalId and EntityImmutableNaturalId
|
||||
// we will select their FKs and all attributes will be "bytecode initialized"
|
||||
assertTrue( Hibernate.isPropertyInitialized( e,"entityMutableNaturalId" ) );
|
||||
assertTrue( Hibernate.isPropertyInitialized( e,"entityImmutableNaturalId" ) );
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
package org.hibernate.test.bytecode.enhancement.lazy.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Cache;
|
||||
|
@ -23,18 +19,21 @@ import org.hibernate.annotations.LazyToOne;
|
|||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.stat.CacheRegionStatistics;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTestCase {
|
||||
|
@ -53,33 +52,21 @@ public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTest
|
|||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-11766")
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void attributeLoadingFromCache() {
|
||||
final AtomicLong bossId = new AtomicLong();
|
||||
final AtomicLong teamleaderId = new AtomicLong();
|
||||
final AtomicLong teammemberId = new AtomicLong();
|
||||
|
||||
TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, (s) -> {
|
||||
Employee boss = new Employee();
|
||||
Employee teamleader = new Employee();
|
||||
Employee teammember = new Employee();
|
||||
boss.regularString = "boss";
|
||||
teamleader.regularString = "leader";
|
||||
teammember.regularString = "member";
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
Employee boss = new Employee( 1, "boss" );
|
||||
Employee teamleader = new Employee( 2, "leader" );
|
||||
Employee teammember = new Employee( 3, "member" );
|
||||
s.persist( boss );
|
||||
s.persist( teamleader );
|
||||
s.persist( teammember );
|
||||
|
||||
boss.subordinates.add( teamleader );
|
||||
teamleader.superior = boss;
|
||||
|
||||
teamleader.subordinates.add( teammember );
|
||||
teammember.superior = teamleader;
|
||||
bossId.set( boss.id );
|
||||
teamleaderId.set( teamleader.id );
|
||||
teammemberId.set( teammember.id );
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -87,19 +74,28 @@ public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTest
|
|||
sessionFactory().getStatistics().clear();
|
||||
CacheRegionStatistics regionStatistics = sessionFactory().getStatistics().getCacheRegionStatistics( "Employee" );
|
||||
|
||||
TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, (s) -> {
|
||||
final Employee boss = s.find( Employee.class, bossId.get() );
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
final Employee boss = s.find( Employee.class, 1 );
|
||||
Assert.assertEquals( "boss", boss.regularString );
|
||||
final Employee leader = s.find( Employee.class, teamleaderId.get() );
|
||||
final Employee leader = s.find( Employee.class, 2 );
|
||||
Assert.assertEquals( "leader", leader.regularString );
|
||||
final Employee member = s.find( Employee.class, teammemberId.get() );
|
||||
final Employee member = s.find( Employee.class, 3 );
|
||||
Assert.assertEquals( "member", member.regularString );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "superior" ) );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) );
|
||||
assertTrue( Hibernate.isInitialized( boss.superior ) );
|
||||
assertThat( boss.superior, not( instanceOf( HibernateProxy.class ) ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "superior" ) );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( leader, "superior" ) );
|
||||
assertTrue( Hibernate.isInitialized( leader.superior ) );
|
||||
assertThat( leader.superior, not( instanceOf( HibernateProxy.class ) ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "superior" ) );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( member, "superior" ) );
|
||||
assertTrue( Hibernate.isInitialized( member.superior ) );
|
||||
assertThat( member.superior, not( instanceOf( HibernateProxy.class ) ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
}
|
||||
);
|
||||
|
@ -108,37 +104,34 @@ public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTest
|
|||
assertEquals( 3, regionStatistics.getMissCount() );
|
||||
assertEquals( 3, regionStatistics.getPutCount() );
|
||||
|
||||
TransactionUtil.doInHibernate(
|
||||
this::sessionFactory, (s) -> {
|
||||
final Employee boss = s.find( Employee.class, bossId.get() );
|
||||
final Employee leader = s.find( Employee.class, teamleaderId.get() );
|
||||
final Employee member = s.find( Employee.class, teammemberId.get() );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) );
|
||||
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
Assert.assertNull( boss.superior );
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
final Employee boss = s.find( Employee.class, 1 );
|
||||
final Employee leader = s.find( Employee.class, 2 );
|
||||
final Employee member = s.find( Employee.class, 3 );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) );
|
||||
Assert.assertEquals( leader, boss.subordinates.iterator().next() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( boss, "subordinates" ) );
|
||||
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) );
|
||||
Assert.assertEquals( boss, leader.superior );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( leader, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) );
|
||||
Assert.assertEquals( member, leader.subordinates.iterator().next() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( leader, "subordinates" ) );
|
||||
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
Assert.assertEquals( leader, member.superior );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( member, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
Assert.assertTrue( member.subordinates.isEmpty() );
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
Assert.assertNull( boss.superior );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) );
|
||||
Assert.assertEquals( leader, boss.subordinates.iterator().next() );
|
||||
assertTrue( Hibernate.isPropertyInitialized( boss, "subordinates" ) );
|
||||
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( leader, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) );
|
||||
Assert.assertEquals( boss, leader.superior );
|
||||
Assert.assertEquals( member, leader.subordinates.iterator().next() );
|
||||
assertTrue( Hibernate.isPropertyInitialized( leader, "subordinates" ) );
|
||||
|
||||
Assert.assertTrue( Hibernate.isPropertyInitialized( member, "superior" ) );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
Assert.assertEquals( leader, member.superior );
|
||||
assertTrue( member.subordinates.isEmpty() );
|
||||
assertTrue( Hibernate.isPropertyInitialized( member, "subordinates" ) );
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -152,10 +145,8 @@ public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTest
|
|||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "Employee")
|
||||
private static class Employee {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
Long id;
|
||||
Integer id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "SUPERIOR")
|
||||
|
@ -167,5 +158,18 @@ public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTest
|
|||
|
||||
@Basic
|
||||
String regularString;
|
||||
|
||||
private Employee() {
|
||||
}
|
||||
|
||||
public Employee(Integer id, String regularString) {
|
||||
this.id = id;
|
||||
this.regularString = regularString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format( "Employee( %s, %s )", id, regularString ) + "@" + System.identityHashCode( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.hibernate.annotations.LazyToOneOption;
|
|||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
|
@ -32,9 +31,10 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -49,10 +49,6 @@ import static org.junit.Assert.assertTrue;
|
|||
EnhancerTestContext.class,
|
||||
BidirectionalLazyGroupsTest.NoDirtyCheckEnhancementContext.class
|
||||
})
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public class BidirectionalLazyGroupsTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -61,11 +57,9 @@ public class BidirectionalLazyGroupsTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testRemoveCollectionOwnerNoCascade() {
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
|
||||
Employer employer = new Employer( "RedHat" );
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Employer employer = new Employer( "RedHat" );
|
||||
session.persist( employer );
|
||||
employer.addEmployee( new Employee( "Jack" ) );
|
||||
employer.addEmployee( new Employee( "Jill" ) );
|
||||
|
@ -76,20 +70,21 @@ public class BidirectionalLazyGroupsTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
Employer employer = session.createQuery( "from Employer e", Employer.class ).getSingleResult();
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Employer employer = session.createQuery( "from Employer e", Employer.class ).getSingleResult();
|
||||
session.remove( employer );
|
||||
for ( Employee employee : employer.getEmployees() ) {
|
||||
assertFalse( Hibernate.isPropertyInitialized( employee, "employer") );
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer") );
|
||||
assertThat( employee.getEmployer(), CoreMatchers.sameInstance( employer ) );
|
||||
|
||||
session.remove( employee );
|
||||
assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
assertNull( session.find( Employer.class, "RedHat" ) );
|
||||
assertNull( session.createQuery( "from Employee e", Employee.class ).uniqueResult() );
|
||||
}
|
||||
|
@ -200,7 +195,7 @@ public class BidirectionalLazyGroupsTest extends BaseCoreFunctionalTestCase {
|
|||
return true;
|
||||
}
|
||||
else if ( o instanceof Employee ) {
|
||||
Employee other = Employee.class.cast( o );
|
||||
Employee other = (Employee) o;
|
||||
if ( name != null ) {
|
||||
return getName().equals( other.getName() );
|
||||
}
|
||||
|
|
|
@ -6,22 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.lazy.group;
|
||||
|
||||
import org.hibernate.annotations.LazyGroup;
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -32,26 +18,39 @@ import javax.persistence.Id;
|
|||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.LazyGroup;
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11155" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlInterceptor;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -62,6 +61,7 @@ public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
|||
protected void configure(Configuration configuration) {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
sqlInterceptor = new SQLStatementInterceptor( configuration );
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -93,39 +93,50 @@ public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
|||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10267" )
|
||||
public void testAccess() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult();
|
||||
sqlInterceptor.clear();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c1, "name" );
|
||||
assertNotLoaded( c1, "nickName" );
|
||||
assertNotLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
final Child c1 = s.createQuery( "from Child c where c.name = :name", Child.class )
|
||||
.setParameter( "name", "steve" )
|
||||
.uniqueResult();
|
||||
|
||||
// Now lets access nickName which ought to initialize nickName and parent, but not alternateParent
|
||||
c1.getNickName();
|
||||
assertLoaded( c1, "nickName" );
|
||||
assertLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
assertEquals( "Hibernate", c1.parent.nombre );
|
||||
assertFalse( c1.parent instanceof HibernateProxy );
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult();
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "name" ) );
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c2, "name" );
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertNotLoaded( c2, "alternateParent" );
|
||||
assertFalse( Hibernate.isPropertyInitialized( c1, "nickName" ) );
|
||||
|
||||
// Now lets access alternateParent which ought to initialize alternateParent and nothing else
|
||||
c2.getAlternateParent();
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertLoaded( c2, "alternateParent" );
|
||||
assertEquals( "Hibernate", c2.alternateParent.nombre );
|
||||
assertFalse( c2.alternateParent instanceof HibernateProxy );
|
||||
} );
|
||||
// parent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) );
|
||||
assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getParent() ) );
|
||||
|
||||
// alternateParent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) );
|
||||
assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) );
|
||||
|
||||
// Now lets access nickName which ought to initialize nickName
|
||||
c1.getNickName();
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 2 ) );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "nickName" ) );
|
||||
|
||||
// parent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) );
|
||||
assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getParent() ) );
|
||||
|
||||
// alternateParent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) );
|
||||
assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) );
|
||||
|
||||
|
||||
sqlInterceptor.clear();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -134,64 +145,66 @@ public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
|||
Parent p1New = new Parent();
|
||||
p1New.nombre = "p1New";
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult();
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
sqlInterceptor.clear();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c1, "name" );
|
||||
assertNotLoaded( c1, "nickName" );
|
||||
assertNotLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
final Child c1 = s.createQuery( "from Child c where c.name = :name", Child.class )
|
||||
.setParameter( "name", "steve" )
|
||||
.uniqueResult();
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
// Now lets update nickName which ought to initialize nickName and parent, but not alternateParent
|
||||
c1.nickName = "new nickName";
|
||||
assertLoaded( c1, "nickName" );
|
||||
assertNotLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
assertEquals( "Hibernate", c1.parent.nombre );
|
||||
assertFalse( c1.parent instanceof HibernateProxy );
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "name" ) );
|
||||
|
||||
// Now update c1.parent
|
||||
c1.parent.children.remove( c1 );
|
||||
c1.parent = p1New;
|
||||
p1New.children.add( c1 );
|
||||
} );
|
||||
assertFalse( Hibernate.isPropertyInitialized( c1, "nickName" ) );
|
||||
|
||||
// parent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) );
|
||||
assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getParent() ) );
|
||||
|
||||
// alternateParent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) );
|
||||
assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) );
|
||||
|
||||
// Now lets update nickName
|
||||
c1.nickName = "new nickName";
|
||||
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "name" ) );
|
||||
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "nickName" ) );
|
||||
|
||||
// parent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) );
|
||||
assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getParent() ) );
|
||||
|
||||
// alternateParent should be an uninitialized enhanced-proxy
|
||||
assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) );
|
||||
assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) );
|
||||
|
||||
// Now update c1.parent
|
||||
c1.parent.children.remove( c1 );
|
||||
c1.parent = p1New;
|
||||
p1New.children.add( c1 );
|
||||
}
|
||||
);
|
||||
|
||||
// verify updates
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult();
|
||||
assertEquals( "new nickName", c1.getNickName() );
|
||||
assertEquals( "p1New", c1.parent.nombre );
|
||||
assertFalse( c1.parent instanceof HibernateProxy );
|
||||
} );
|
||||
inTransaction(
|
||||
(s) -> {
|
||||
final Child c1 = s.createQuery( "from Child c where c.name = :name", Child.class )
|
||||
.setParameter( "name", "steve" )
|
||||
.uniqueResult();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c2, "name" );
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertNotLoaded( c2, "alternateParent" );
|
||||
|
||||
// Now lets access and update alternateParent which ought to initialize alternateParent and nothing else
|
||||
Parent p1 = c2.getAlternateParent();
|
||||
c2.alternateParent = p1New;
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertLoaded( c2, "alternateParent" );
|
||||
assertEquals( "p1New", c2.getAlternateParent().nombre );
|
||||
assertFalse( c2.getAlternateParent() instanceof HibernateProxy );
|
||||
|
||||
p1.alternateChildren.remove( c2 );
|
||||
p1New.alternateChildren.add( c2 );
|
||||
} );
|
||||
|
||||
// verify update
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult();
|
||||
assertEquals( "p1New", c2.getAlternateParent().nombre );
|
||||
} );
|
||||
assertThat( c1.getNickName(), is( "new nickName" ) );
|
||||
assertThat( c1.parent.nombre, is( "p1New" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -204,18 +217,6 @@ public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
// --- //
|
||||
|
||||
private void assertLoaded(Object owner, String name) {
|
||||
// NOTE we assume null == not-loaded
|
||||
Object fieldByReflection = getFieldByReflection( owner, name );
|
||||
assertNotNull( "Expecting field '" + name + "' to be loaded, but it was not", fieldByReflection );
|
||||
}
|
||||
|
||||
private void assertNotLoaded(Object owner, String name) {
|
||||
// NOTE we assume null == not-loaded
|
||||
Object fieldByReflection = getFieldByReflection( owner, name );
|
||||
assertNull( "Expecting field '" + name + "' to be not loaded, but it was", fieldByReflection );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Parent" )
|
||||
|
@ -271,6 +272,10 @@ public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
|||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public Parent getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
Parent getAlternateParent() {
|
||||
return alternateParent;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.lazy.notfound;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -26,7 +22,6 @@ import org.hibernate.annotations.LazyToOneOption;
|
|||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
@ -37,6 +32,9 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-12226")
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyNotFoundManyToOneNonUpdatableNonInsertableTest extends BaseCoreFunctionalTestCase {
|
||||
|
@ -51,10 +49,6 @@ public class LazyNotFoundManyToOneNonUpdatableNonInsertableTest extends BaseCore
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void test() {
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.hibernate.annotations.NotFoundAction;
|
|||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.lazy.notfound;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.ConstraintMode;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -28,23 +24,29 @@ import org.hibernate.annotations.NotFoundAction;
|
|||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-12226")
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyNotFoundOneToOneTest extends BaseCoreFunctionalTestCase {
|
||||
private static int ID = 1;
|
||||
|
||||
private SQLStatementInterceptor sqlInterceptor;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
|
@ -56,14 +58,10 @@ public class LazyNotFoundOneToOneTest extends BaseCoreFunctionalTestCase {
|
|||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure(configuration);
|
||||
configuration.setProperty( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||
sqlInterceptor = new SQLStatementInterceptor( configuration );
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void test() {
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
|
@ -82,10 +80,15 @@ public class LazyNotFoundOneToOneTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
sqlInterceptor.clear();
|
||||
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
User user = session.find( User.class, ID );
|
||||
|
||||
assertThat( sqlInterceptor.getQueryCount(), is( 1 ) );
|
||||
assertFalse( Hibernate.isPropertyInitialized( user, "lazy" ) );
|
||||
|
||||
assertNull( user.getLazy() );
|
||||
}
|
||||
);
|
||||
|
|
|
@ -200,7 +200,6 @@ public class FetchGraphTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13658")
|
||||
public void testRandomAccess() {
|
||||
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
|
|
|
@ -10,24 +10,28 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.stat.Statistics;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.bytecode.enhancement.lazy.group.BidirectionalLazyGroupsInEmbeddableTest;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
|
@ -39,10 +43,25 @@ import static org.junit.Assert.assertEquals;
|
|||
@EnhancementOptions( lazyLoading = true )
|
||||
public class LazyGroupWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
@Test
|
||||
@FailureExpected(
|
||||
jiraKey = "HHH-13658",
|
||||
message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid"
|
||||
)
|
||||
public void loadEntityWithAssociationToAbstract() {
|
||||
final Statistics stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Order loaded = session.byId( Order.class ).load( 1 );
|
||||
assert Hibernate.isPropertyInitialized( loaded, "customer" );
|
||||
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||
assertThat( loaded, instanceOf( PersistentAttributeInterceptable.class ) );
|
||||
final PersistentAttributeInterceptor interceptor = ((PersistentAttributeInterceptable) loaded).$$_hibernate_getInterceptor();
|
||||
assertThat( interceptor, instanceOf( BytecodeLazyAttributeInterceptor.class ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor1 = (BytecodeLazyAttributeInterceptor) interceptor;
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryEntityWithAssociationToAbstract() {
|
||||
final Statistics stats = sessionFactory().getStatistics();
|
||||
stats.clear();
|
||||
|
@ -61,8 +80,8 @@ public class LazyGroupWithInheritanceTest extends BaseNonConfigCoreFunctionalTes
|
|||
// The only viable solution I see would be to join to the "other side" and read the
|
||||
// version/discriminator[1]. But of course that means doing the join which is generally
|
||||
// what the application is trying to avoid in the first place
|
||||
//expectedQueryCount.set( 1 );
|
||||
expectedQueryCount.set( 4 );
|
||||
expectedQueryCount.set( 1 );
|
||||
//expectedQueryCount.set( 4 );
|
||||
assertEquals( expectedQueryCount.get(), stats.getPrepareStatementCount() );
|
||||
|
||||
for ( Order order : orders ) {
|
||||
|
|
|
@ -84,7 +84,7 @@ public class CustomPersister implements EntityPersister {
|
|||
NaturalIdDataAccess naturalIdRegionAccessStrategy,
|
||||
PersisterCreationContext creationContext) {
|
||||
this.factory = creationContext.getSessionFactory();
|
||||
this.entityMetamodel = new EntityMetamodel( model, this, factory );
|
||||
this.entityMetamodel = new EntityMetamodel( model, this, creationContext );
|
||||
}
|
||||
|
||||
public boolean hasLazyProperties() {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.test.mapping.lazytoone;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
@ -24,6 +25,8 @@ import static org.hibernate.annotations.LazyToOneOption.NO_PROXY;
|
|||
public class Flight {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@Column( name = "flight_number" )
|
||||
private String number;
|
||||
|
||||
@ManyToOne( fetch = LAZY )
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.FetchMode.JOIN;
|
||||
|
||||
/**
|
||||
* Test for lazy uni-directional to-one (with JOIN fetching) when enhanced proxies are allowed
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class JoinFetchedManyToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( Order.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final Order order = new Order( 1, customer, BigDecimal.ONE );
|
||||
session.persist( order );
|
||||
}
|
||||
);
|
||||
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class );
|
||||
final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Order order = session.byId( Order.class ).getReference( 1 );
|
||||
|
||||
// we should have an uninitialized enhanced proxy - therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = orderEnhancementMetadata.extractLazyInterceptor( order );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// access the id - should do nothing with db
|
||||
order.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( initialInterceptor, sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) );
|
||||
|
||||
// this should trigger loading the entity's base state which includes customer.
|
||||
// and since customer is defined for join fetch we
|
||||
order.getAmount();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
assertThat( initialInterceptor, not( sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) ) );
|
||||
|
||||
// should not trigger a load - Order's base fetch state includes customer
|
||||
final Customer customer = order.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
// and since Order#customer is mapped for JOIN fetching, Customer should be fully initialized as well
|
||||
assertThat( Hibernate.isInitialized( customer ), is( true ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Order")
|
||||
@Table( name = "`order`")
|
||||
public static class Order {
|
||||
@Id
|
||||
private Integer id;
|
||||
@ManyToOne( fetch = LAZY )
|
||||
@Fetch( JOIN )
|
||||
//we want it to behave as if...
|
||||
//@LazyToOne( NO_PROXY )
|
||||
private Customer customer;
|
||||
private BigDecimal amount;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(Integer id, Customer customer, BigDecimal amount) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Test for lazy uni-directional to-one (with SELECT fetching) when enhanced proxies are allowed
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class ManyToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( Order.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class );
|
||||
final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Order order = session.byId( Order.class ).getReference( 1 );
|
||||
|
||||
// we should have just the uninitialized proxy of the owner - and
|
||||
// therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = orderEnhancementMetadata.extractLazyInterceptor( order );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// access the id - should do nothing with db
|
||||
order.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( initialInterceptor, sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) );
|
||||
|
||||
// this should trigger loading the entity's base state
|
||||
order.getAmount();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor = orderEnhancementMetadata.extractLazyInterceptor( order );
|
||||
assertThat( initialInterceptor, not( sameInstance( interceptor ) ) );
|
||||
assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor;
|
||||
assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) );
|
||||
|
||||
// should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy
|
||||
final Customer customer = order.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer );
|
||||
assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final Order order = new Order( 1, customer, BigDecimal.ONE );
|
||||
session.persist( order );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Order" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Order")
|
||||
@Table( name = "`order`")
|
||||
public static class Order {
|
||||
@Id
|
||||
private Integer id;
|
||||
@ManyToOne( fetch = LAZY )
|
||||
//we want it to behave as if...
|
||||
//@LazyToOne( NO_PROXY )
|
||||
private Customer customer;
|
||||
private BigDecimal amount;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(Integer id, Customer customer, BigDecimal amount) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.LazyToOneOption.NO_PROXY;
|
||||
|
||||
/**
|
||||
* Baseline test for uni-directional to-one, using an explicit @LazyToOne(NO_PROXY)
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class ManyToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( Order.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final Order order = new Order( 1, customer, BigDecimal.ONE );
|
||||
session.persist( order );
|
||||
}
|
||||
);
|
||||
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class );
|
||||
final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Order order = session.byId( Order.class ).getReference( 1 );
|
||||
|
||||
// we should have just the uninitialized proxy of the owner - and
|
||||
// therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = orderEnhancementMetadata.extractLazyInterceptor( order );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// access the id - should do nothing with db
|
||||
order.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( initialInterceptor, sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) );
|
||||
|
||||
// this should trigger loading the entity's base state
|
||||
order.getAmount();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor = orderEnhancementMetadata.extractLazyInterceptor( order );
|
||||
assertThat( initialInterceptor, not( sameInstance( interceptor ) ) );
|
||||
assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor;
|
||||
assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) );
|
||||
|
||||
// should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy
|
||||
final Customer customer = order.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer );
|
||||
assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Order" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Order")
|
||||
@Table( name = "`order`")
|
||||
public static class Order {
|
||||
@Id
|
||||
private Integer id;
|
||||
@ManyToOne( fetch = LAZY )
|
||||
@LazyToOne( NO_PROXY )
|
||||
private Customer customer;
|
||||
private BigDecimal amount;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(Integer id, Customer customer, BigDecimal amount) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.mappedby;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class InverseToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( SupplementalInfo.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class );
|
||||
final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
|
||||
// Get a reference to the SupplementalInfo we created
|
||||
|
||||
final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 );
|
||||
|
||||
// 1) we should have just the uninitialized SupplementalInfo enhanced proxy
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// (2) Access the SupplementalInfo's id value - should trigger no SQL
|
||||
|
||||
supplementalInfo.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( initialInterceptor, sameInstance( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ) ) );
|
||||
|
||||
// 3) Access SupplementalInfo's `something` state
|
||||
// - should trigger loading the "base group" state, which only include `something`.
|
||||
// NOTE: `customer` is not part of this lazy group because we do not know the
|
||||
// Customer PK from this side
|
||||
supplementalInfo.getSomething();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, not( sameInstance( interceptor ) ) );
|
||||
assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
|
||||
// 4) Access SupplementalInfo's `customer` state
|
||||
// - should trigger load from Customer table, by FK
|
||||
final Customer customer = supplementalInfo.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" );
|
||||
session.persist( supplementalInfo );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
session.createQuery( "delete SupplementalInfo" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
@OneToOne( fetch = LAZY )
|
||||
private SupplementalInfo supplementalInfo;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public SupplementalInfo getSupplementalInfo() {
|
||||
return supplementalInfo;
|
||||
}
|
||||
|
||||
public void setSupplementalInfo(SupplementalInfo supplementalInfo) {
|
||||
this.supplementalInfo = supplementalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "SupplementalInfo" )
|
||||
@Table( name = "supplemental" )
|
||||
public static class SupplementalInfo {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne( fetch = LAZY, mappedBy = "supplementalInfo", optional = false )
|
||||
// @LazyToOne( value = NO_PROXY )
|
||||
private Customer customer;
|
||||
|
||||
private String something;
|
||||
|
||||
public SupplementalInfo() {
|
||||
}
|
||||
|
||||
public SupplementalInfo(Integer id, Customer customer, String something) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.something = something;
|
||||
|
||||
customer.setSupplementalInfo( this );
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getSomething() {
|
||||
return something;
|
||||
}
|
||||
|
||||
public void setSomething(String something) {
|
||||
this.something = something;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.mappedby;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.LazyToOneOption.NO_PROXY;
|
||||
|
||||
/**
|
||||
* Baseline test for inverse (mappedBy) to-one, using an explicit @LazyToOne(NO_PROXY)
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class InverseToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( SupplementalInfo.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" );
|
||||
session.persist( supplementalInfo );
|
||||
}
|
||||
);
|
||||
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class );
|
||||
final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
|
||||
// 1) Get a reference to the SupplementalInfo we created
|
||||
// - at that point there should be no SQL executed
|
||||
// 2) Access the SupplementalInfo's id value
|
||||
// - should trigger no SQL
|
||||
// 3) Access SupplementalInfo's `something` state
|
||||
// - should trigger loading the "base group" state, which only include `something`.
|
||||
// NOTE: `customer` is not part of this lazy group because we do not know the
|
||||
// Customer PK from this side
|
||||
// 4) Access SupplementalInfo's `customer` state
|
||||
// - should trigger load from Customer table
|
||||
|
||||
final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 );
|
||||
|
||||
// we should have just the uninitialized SupplementalInfo proxy
|
||||
// - therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
assertThat(
|
||||
supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ),
|
||||
instanceOf( EnhancementAsProxyLazinessInterceptor.class )
|
||||
);
|
||||
|
||||
// access the id - should do nothing with db
|
||||
supplementalInfo.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat(
|
||||
supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ),
|
||||
instanceOf( EnhancementAsProxyLazinessInterceptor.class )
|
||||
);
|
||||
|
||||
// this should trigger loading the entity's base state
|
||||
supplementalInfo.getSomething();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
assertThat(
|
||||
supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ),
|
||||
instanceOf( LazyAttributeLoadingInterceptor.class )
|
||||
);
|
||||
|
||||
// because we do not know the customer FK from the SupplementalInfo side
|
||||
// it is considered part of SupplementalInfo's non-base state.
|
||||
//
|
||||
// here we access customer which triggers a load from customer table
|
||||
final Customer customer = supplementalInfo.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
|
||||
assertThat(
|
||||
customerEnhancementMetadata.extractLazyInterceptor( customer ),
|
||||
instanceOf( LazyAttributeLoadingInterceptor.class )
|
||||
);
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
session.createQuery( "delete SupplementalInfo" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
@OneToOne( fetch = LAZY )
|
||||
private SupplementalInfo supplementalInfo;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public SupplementalInfo getSupplementalInfo() {
|
||||
return supplementalInfo;
|
||||
}
|
||||
|
||||
public void setSupplementalInfo(SupplementalInfo supplementalInfo) {
|
||||
this.supplementalInfo = supplementalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "SupplementalInfo" )
|
||||
@Table( name = "supplemental" )
|
||||
public static class SupplementalInfo {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne( fetch = LAZY, mappedBy = "supplementalInfo", optional = false )
|
||||
@LazyToOne( value = NO_PROXY )
|
||||
private Customer customer;
|
||||
|
||||
private String something;
|
||||
|
||||
public SupplementalInfo() {
|
||||
}
|
||||
|
||||
public SupplementalInfo(Integer id, Customer customer, String something) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.something = something;
|
||||
|
||||
customer.setSupplementalInfo( this );
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getSomething() {
|
||||
return something;
|
||||
}
|
||||
|
||||
public void setSomething(String something) {
|
||||
this.something = something;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.mappedby;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.FetchMode.JOIN;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class JoinFetchedInverseToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( SupplementalInfo.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class );
|
||||
final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
|
||||
// Get a reference to the SupplementalInfo we created
|
||||
|
||||
final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 );
|
||||
|
||||
// 1) we should have just the uninitialized SupplementalInfo enhanced proxy
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// 2) Access the SupplementalInfo's id value - should trigger no SQL
|
||||
|
||||
supplementalInfo.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( initialInterceptor, sameInstance( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ) ) );
|
||||
|
||||
// 3) Access SupplementalInfo's `something` state
|
||||
// - should trigger loading the "base group" state
|
||||
// - customer should be join fetched as part of loading this base state
|
||||
supplementalInfo.getSomething();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, not( sameInstance( interceptor ) ) );
|
||||
assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
|
||||
// 4) Access SupplementalInfo's `customer` state
|
||||
final Customer customer = supplementalInfo.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
customer.getId();
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" );
|
||||
session.persist( supplementalInfo );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
session.createQuery( "delete SupplementalInfo" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
@OneToOne( fetch = LAZY )
|
||||
private SupplementalInfo supplementalInfo;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public SupplementalInfo getSupplementalInfo() {
|
||||
return supplementalInfo;
|
||||
}
|
||||
|
||||
public void setSupplementalInfo(SupplementalInfo supplementalInfo) {
|
||||
this.supplementalInfo = supplementalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "SupplementalInfo" )
|
||||
@Table( name = "supplemental" )
|
||||
public static class SupplementalInfo {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne( fetch = LAZY, mappedBy = "supplementalInfo", optional = false )
|
||||
// @LazyToOne( value = NO_PROXY )
|
||||
@Fetch( JOIN )
|
||||
private Customer customer;
|
||||
|
||||
private String something;
|
||||
|
||||
public SupplementalInfo() {
|
||||
}
|
||||
|
||||
public SupplementalInfo(Integer id, Customer customer, String something) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.something = something;
|
||||
|
||||
customer.setSupplementalInfo( this );
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getSomething() {
|
||||
return something;
|
||||
}
|
||||
|
||||
public void setSomething(String something) {
|
||||
this.something = something;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.onetoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.FetchMode.JOIN;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class JoinFetchedOneToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( SupplementalInfo.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class );
|
||||
final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 );
|
||||
|
||||
// we should have just the uninitialized SupplementalInfo proxy
|
||||
// - therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
// access the id - should do nothing with db
|
||||
supplementalInfo.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
// this should trigger loading the entity's base state which should include join fetching Customer
|
||||
supplementalInfo.getSomething();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
// should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy
|
||||
final Customer customer = supplementalInfo.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" );
|
||||
session.persist( supplementalInfo );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete SupplementalInfo" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "SupplementalInfo" )
|
||||
@Table( name = "supplemental" )
|
||||
public static class SupplementalInfo {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne( fetch = LAZY, optional = false )
|
||||
@Fetch( JOIN )
|
||||
//@LazyToOne( value = NO_PROXY )
|
||||
private Customer customer;
|
||||
|
||||
private String something;
|
||||
|
||||
public SupplementalInfo() {
|
||||
}
|
||||
|
||||
public SupplementalInfo(Integer id, Customer customer, String something) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.something = something;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getSomething() {
|
||||
return something;
|
||||
}
|
||||
|
||||
public void setSomething(String something) {
|
||||
this.something = something;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.onetoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class OneToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( SupplementalInfo.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class );
|
||||
final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 );
|
||||
|
||||
// we should have just the uninitialized SupplementalInfo proxy
|
||||
// - therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// access the id - should do nothing with db
|
||||
supplementalInfo.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), sameInstance( initialInterceptor ) );
|
||||
|
||||
// this should trigger loading the entity's base state
|
||||
supplementalInfo.getSomething();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, not( sameInstance( interceptor ) ) );
|
||||
assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor;
|
||||
assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) );
|
||||
|
||||
// should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy
|
||||
final Customer customer = supplementalInfo.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer );
|
||||
assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" );
|
||||
session.persist( supplementalInfo );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete SupplementalInfo" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "SupplementalInfo" )
|
||||
@Table( name = "supplemental" )
|
||||
public static class SupplementalInfo {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne( fetch = LAZY, optional = false )
|
||||
//@LazyToOne( value = NO_PROXY )
|
||||
private Customer customer;
|
||||
|
||||
private String something;
|
||||
|
||||
public SupplementalInfo() {
|
||||
}
|
||||
|
||||
public SupplementalInfo(Integer id, Customer customer, String something) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.something = something;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getSomething() {
|
||||
return something;
|
||||
}
|
||||
|
||||
public void setSomething(String something) {
|
||||
this.something = something;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.onetoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.LazyToOneOption.NO_PROXY;
|
||||
|
||||
/**
|
||||
* Baseline test for uni-directional one-to-one, using an explicit @LazyToOne(NO_PROXY) and allowing enhanced proxies
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class OneToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( SupplementalInfo.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOwnerIsProxy() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class );
|
||||
final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class );
|
||||
final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata();
|
||||
assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) );
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 );
|
||||
|
||||
// we should have just the uninitialized SupplementalInfo proxy
|
||||
// - therefore no SQL statements should have been executed
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// access the id - should do nothing with db
|
||||
supplementalInfo.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) );
|
||||
assertThat( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), sameInstance( initialInterceptor ) );
|
||||
|
||||
// this should trigger loading the entity's base state
|
||||
supplementalInfo.getSomething();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo );
|
||||
assertThat( initialInterceptor, not( sameInstance( interceptor ) ) );
|
||||
assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor;
|
||||
assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) );
|
||||
|
||||
// should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy
|
||||
final Customer customer = supplementalInfo.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
|
||||
final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer );
|
||||
assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
// just as above, accessing id should trigger no loads
|
||||
customer.getId();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) );
|
||||
assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) );
|
||||
assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Customer customer = new Customer( 1, "Acme Brick" );
|
||||
session.persist( customer );
|
||||
final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" );
|
||||
session.persist( supplementalInfo );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete SupplementalInfo" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Table( name = "customer" )
|
||||
public static class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "SupplementalInfo" )
|
||||
@Table( name = "supplemental" )
|
||||
public static class SupplementalInfo {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne( fetch = LAZY, optional = false )
|
||||
@LazyToOne( value = NO_PROXY )
|
||||
private Customer customer;
|
||||
|
||||
private String something;
|
||||
|
||||
public SupplementalInfo() {
|
||||
}
|
||||
|
||||
public SupplementalInfo(Integer id, Customer customer, String something) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
this.something = something;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getSomething() {
|
||||
return something;
|
||||
}
|
||||
|
||||
public void setSomething(String something) {
|
||||
this.something = something;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.polymorphic;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.annotations.FetchMode.JOIN;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class JoinFetchedPolymorphicToOneTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
@Test
|
||||
public void testInheritedToOneLaziness() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final Order order = session.byId( Order.class ).getReference( 1 );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) );
|
||||
|
||||
System.out.println( "Order # " + order.getId() );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) );
|
||||
|
||||
System.out.println( " - amount : " + order.getAmount() );
|
||||
// triggers load of base fetch state
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
final Customer customer = order.getCustomer();
|
||||
// customer is part of base fetch state
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
assertTrue( Hibernate.isInitialized( customer ) );
|
||||
|
||||
System.out.println( " - customer : " + customer.getId() );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
customer.getName();
|
||||
// customer base fetch state should also have been loaded above
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final DomesticCustomer customer = new DomesticCustomer( 1, "them", "123" );
|
||||
session.persist( customer );
|
||||
final Order order = new Order( 1, BigDecimal.ONE, customer );
|
||||
session.persist( order );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Order" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Order.class );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( ForeignCustomer.class );
|
||||
sources.addAnnotatedClass( DomesticCustomer.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Entity( name = "Order" )
|
||||
@Table( name = "`order`" )
|
||||
public static class Order {
|
||||
@Id
|
||||
private Integer id;
|
||||
private BigDecimal amount;
|
||||
@ManyToOne( fetch = LAZY, optional = false )
|
||||
@Fetch( JOIN )
|
||||
private Customer customer;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(Integer id, BigDecimal amount, Customer customer) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS )
|
||||
public static abstract class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "ForeignCustomer")
|
||||
@Table(name = "foreign_cust")
|
||||
public static class ForeignCustomer extends Customer {
|
||||
private String vat;
|
||||
|
||||
public ForeignCustomer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ForeignCustomer(Integer id, String name, String vat) {
|
||||
super( id, name );
|
||||
this.vat = vat;
|
||||
}
|
||||
|
||||
public String getVat() {
|
||||
return vat;
|
||||
}
|
||||
|
||||
public void setVat(String vat) {
|
||||
this.vat = vat;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "DomesticCustomer")
|
||||
@Table(name = "domestic_cust")
|
||||
public static class DomesticCustomer extends Customer {
|
||||
private String taxId;
|
||||
|
||||
public DomesticCustomer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DomesticCustomer(Integer id, String name, String taxId) {
|
||||
super( id, name );
|
||||
this.taxId = taxId;
|
||||
}
|
||||
|
||||
public String getTaxId() {
|
||||
return taxId;
|
||||
}
|
||||
|
||||
public void setTaxId(String taxId) {
|
||||
this.taxId = taxId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.polymorphic;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class PolymorphicToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
@Test
|
||||
public void testInheritedToOneLaziness() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
// NOTE : this test shows an edge case that does not work the way it
|
||||
// should. Because we have a polymorphic to-one, we will have to
|
||||
// generate a HibernateProxy for the laziness. However, the explicit
|
||||
// NO_PROXY should force the proxy to be immediately initialized
|
||||
// and the target returned.
|
||||
//
|
||||
// this is the old behavior as well - these HHH-13658 changes did not cause this
|
||||
//
|
||||
// its an odd edge case however and maybe not that critical. it essentially
|
||||
// asks for the association to be lazy and to also be eager
|
||||
//
|
||||
// The assertions here are based on what *does* happen. Whether that is right/wrong
|
||||
// is a different discussion
|
||||
|
||||
final Order order = session.byId( Order.class ).getReference( 1 );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) );
|
||||
|
||||
System.out.println( "Order # " + order.getId() );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) );
|
||||
|
||||
System.out.println( " - amount : " + order.getAmount() );
|
||||
// triggers load of base fetch state
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
final Customer customer = order.getCustomer();
|
||||
// this *should* be 2 - the customer should get loaded
|
||||
//int expectedCount = 2;
|
||||
// but it is 1 because we get back a HibernateProxy
|
||||
int expectedCount = 1;
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( expectedCount ) );
|
||||
// should be true...
|
||||
//assertTrue( Hibernate.isInitialized( customer ) );
|
||||
// but is false
|
||||
assertFalse( Hibernate.isInitialized( customer ) );
|
||||
// should not be a HibernateProxy
|
||||
//assertThat( customer, not( instanceOf( HibernateProxy.class ) ) );
|
||||
// but is
|
||||
assertThat( customer, instanceOf( HibernateProxy.class ) );
|
||||
|
||||
System.out.println( " - customer : " + customer.getId() );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( expectedCount ) );
|
||||
|
||||
customer.getName();
|
||||
// this should not trigger SQL because the customer ought to already be initialized
|
||||
// but again that is not the case
|
||||
expectedCount++;
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( expectedCount ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final DomesticCustomer customer = new DomesticCustomer( 1, "them", "123" );
|
||||
session.persist( customer );
|
||||
final Order order = new Order( 1, BigDecimal.ONE, customer );
|
||||
session.persist( order );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Order" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Order.class );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( ForeignCustomer.class );
|
||||
sources.addAnnotatedClass( DomesticCustomer.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Entity( name = "Order" )
|
||||
@Table( name = "`order`" )
|
||||
public static class Order {
|
||||
@Id
|
||||
private Integer id;
|
||||
private BigDecimal amount;
|
||||
@ManyToOne( fetch = LAZY, optional = false )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
private Customer customer;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(Integer id, BigDecimal amount, Customer customer) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS )
|
||||
public static abstract class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "ForeignCustomer")
|
||||
@Table(name = "foreign_cust")
|
||||
public static class ForeignCustomer extends Customer {
|
||||
private String vat;
|
||||
|
||||
public ForeignCustomer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ForeignCustomer(Integer id, String name, String vat) {
|
||||
super( id, name );
|
||||
this.vat = vat;
|
||||
}
|
||||
|
||||
public String getVat() {
|
||||
return vat;
|
||||
}
|
||||
|
||||
public void setVat(String vat) {
|
||||
this.vat = vat;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "DomesticCustomer")
|
||||
@Table(name = "domestic_cust")
|
||||
public static class DomesticCustomer extends Customer {
|
||||
private String taxId;
|
||||
|
||||
public DomesticCustomer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DomesticCustomer(Integer id, String name, String taxId) {
|
||||
super( id, name );
|
||||
this.taxId = taxId;
|
||||
}
|
||||
|
||||
public String getTaxId() {
|
||||
return taxId;
|
||||
}
|
||||
|
||||
public void setTaxId(String taxId) {
|
||||
this.taxId = taxId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* 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.test.mapping.lazytoone.polymorphic;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class)
|
||||
@EnhancementOptions( lazyLoading = true )
|
||||
public class PolymorphicToOneImplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase {
|
||||
@Test
|
||||
public void testInheritedToOneLaziness() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
final Order order = session.byId( Order.class ).getReference( 1 );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) );
|
||||
|
||||
System.out.println( "Order # " + order.getId() );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) );
|
||||
|
||||
System.out.println( " - amount : " + order.getAmount() );
|
||||
// triggers load of base fetch state
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
final Customer customer = order.getCustomer();
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
// customer is part of base fetch state
|
||||
assertFalse( Hibernate.isInitialized( customer ) );
|
||||
assertThat( customer, instanceOf( HibernateProxy.class ) );
|
||||
|
||||
System.out.println( " - customer : " + customer.getId() );
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) );
|
||||
|
||||
customer.getName();
|
||||
assertThat( sqlStatementInterceptor.getQueryCount(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final DomesticCustomer customer = new DomesticCustomer( 1, "them", "123" );
|
||||
session.persist( customer );
|
||||
final Order order = new Order( 1, BigDecimal.ONE, customer );
|
||||
session.persist( order );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@After
|
||||
public void dropTestData() {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Order" ).executeUpdate();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
super.applyMetadataSources( sources );
|
||||
sources.addAnnotatedClass( Order.class );
|
||||
sources.addAnnotatedClass( Customer.class );
|
||||
sources.addAnnotatedClass( ForeignCustomer.class );
|
||||
sources.addAnnotatedClass( DomesticCustomer.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true );
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( ssrb );
|
||||
}
|
||||
|
||||
@Entity( name = "Order" )
|
||||
@Table( name = "`order`" )
|
||||
public static class Order {
|
||||
@Id
|
||||
private Integer id;
|
||||
private BigDecimal amount;
|
||||
@ManyToOne( fetch = LAZY, optional = false )
|
||||
private Customer customer;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(Integer id, BigDecimal amount, Customer customer) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS )
|
||||
public static abstract class Customer {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "ForeignCustomer")
|
||||
@Table(name = "foreign_cust")
|
||||
public static class ForeignCustomer extends Customer {
|
||||
private String vat;
|
||||
|
||||
public ForeignCustomer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ForeignCustomer(Integer id, String name, String vat) {
|
||||
super( id, name );
|
||||
this.vat = vat;
|
||||
}
|
||||
|
||||
public String getVat() {
|
||||
return vat;
|
||||
}
|
||||
|
||||
public void setVat(String vat) {
|
||||
this.vat = vat;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "DomesticCustomer")
|
||||
@Table(name = "domestic_cust")
|
||||
public static class DomesticCustomer extends Customer {
|
||||
private String taxId;
|
||||
|
||||
public DomesticCustomer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DomesticCustomer(Integer id, String name, String taxId) {
|
||||
super( id, name );
|
||||
this.taxId = taxId;
|
||||
}
|
||||
|
||||
public String getTaxId() {
|
||||
return taxId;
|
||||
}
|
||||
|
||||
public void setTaxId(String taxId) {
|
||||
this.taxId = taxId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,9 @@ import java.util.LinkedList;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -39,6 +41,20 @@ public class SQLStatementInterceptor {
|
|||
} );
|
||||
}
|
||||
|
||||
public SQLStatementInterceptor(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting(
|
||||
AvailableSettings.STATEMENT_INSPECTOR,
|
||||
(StatementInspector) sql -> {
|
||||
sqlQueries.add( sql );
|
||||
return sql;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public SQLStatementInterceptor(Configuration configuration) {
|
||||
this( configuration.getProperties() );
|
||||
}
|
||||
|
||||
public LinkedList<String> getSqlQueries() {
|
||||
return sqlQueries;
|
||||
}
|
||||
|
@ -54,4 +70,8 @@ public class SQLStatementInterceptor {
|
|||
public void assertExecutedCount(int expected) {
|
||||
assertEquals(expected, sqlQueries.size());
|
||||
}
|
||||
|
||||
public int getQueryCount() {
|
||||
return sqlQueries.size();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue