Merge remote-tracking branch 'upstream5/master' into wip/6.0_merged_8
This commit is contained in:
commit
39afae5462
|
@ -62,10 +62,10 @@ public class MetadataSources implements Serializable {
|
||||||
|
|
||||||
private XmlMappingBinderAccess xmlMappingBinderAccess;
|
private XmlMappingBinderAccess xmlMappingBinderAccess;
|
||||||
|
|
||||||
private List<Binding> xmlBindings = new ArrayList<>();
|
private List<Binding> xmlBindings;
|
||||||
private LinkedHashSet<Class<?>> annotatedClasses = new LinkedHashSet<>();
|
private LinkedHashSet<Class<?>> annotatedClasses;
|
||||||
private LinkedHashSet<String> annotatedClassNames = new LinkedHashSet<>();
|
private LinkedHashSet<String> annotatedClassNames;
|
||||||
private LinkedHashSet<String> annotatedPackages = new LinkedHashSet<>();
|
private LinkedHashSet<String> annotatedPackages;
|
||||||
|
|
||||||
private Map<String,Class<?>> extraQueryImports;
|
private Map<String,Class<?>> extraQueryImports;
|
||||||
|
|
||||||
|
@ -81,14 +81,15 @@ public class MetadataSources implements Serializable {
|
||||||
public MetadataSources(ServiceRegistry serviceRegistry) {
|
public MetadataSources(ServiceRegistry serviceRegistry) {
|
||||||
// service registry really should be either BootstrapServiceRegistry or StandardServiceRegistry type...
|
// service registry really should be either BootstrapServiceRegistry or StandardServiceRegistry type...
|
||||||
if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) {
|
if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) {
|
||||||
|
if ( LOG.isDebugEnabled() ) {
|
||||||
LOG.debugf(
|
LOG.debugf(
|
||||||
"Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " +
|
"Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " +
|
||||||
"problems later attempting to construct MetadataBuilder",
|
"problems later attempting to construct MetadataBuilder",
|
||||||
serviceRegistry.getClass().getName()
|
serviceRegistry.getClass().getName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.serviceRegistry = serviceRegistry;
|
this.serviceRegistry = serviceRegistry;
|
||||||
this.xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) {
|
protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) {
|
||||||
|
@ -97,23 +98,26 @@ public class MetadataSources implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlMappingBinderAccess getXmlMappingBinderAccess() {
|
public XmlMappingBinderAccess getXmlMappingBinderAccess() {
|
||||||
|
if ( xmlMappingBinderAccess == null ) {
|
||||||
|
xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry );
|
||||||
|
}
|
||||||
return xmlMappingBinderAccess;
|
return xmlMappingBinderAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Binding> getXmlBindings() {
|
public List<Binding> getXmlBindings() {
|
||||||
return xmlBindings;
|
return xmlBindings == null ? Collections.emptyList() : xmlBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getAnnotatedPackages() {
|
public Collection<String> getAnnotatedPackages() {
|
||||||
return annotatedPackages;
|
return annotatedPackages == null ? Collections.emptySet() : annotatedPackages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Class<?>> getAnnotatedClasses() {
|
public Collection<Class<?>> getAnnotatedClasses() {
|
||||||
return annotatedClasses;
|
return annotatedClasses == null ? Collections.emptySet() : annotatedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getAnnotatedClassNames() {
|
public Collection<String> getAnnotatedClassNames() {
|
||||||
return annotatedClassNames;
|
return annotatedClassNames == null ? Collections.emptySet() : annotatedClassNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String,Class<?>> getExtraQueryImports() {
|
public Map<String,Class<?>> getExtraQueryImports() {
|
||||||
|
@ -201,6 +205,9 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining)
|
* @return this (for method chaining)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addAnnotatedClass(Class annotatedClass) {
|
public MetadataSources addAnnotatedClass(Class annotatedClass) {
|
||||||
|
if ( annotatedClasses == null ) {
|
||||||
|
annotatedClasses = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
annotatedClasses.add( annotatedClass );
|
annotatedClasses.add( annotatedClass );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -225,6 +232,9 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining)
|
* @return this (for method chaining)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addAnnotatedClassName(String annotatedClassName) {
|
public MetadataSources addAnnotatedClassName(String annotatedClassName) {
|
||||||
|
if ( annotatedClassNames == null ) {
|
||||||
|
annotatedClassNames = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
annotatedClassNames.add( annotatedClassName );
|
annotatedClassNames.add( annotatedClassName );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -265,11 +275,17 @@ public class MetadataSources implements Serializable {
|
||||||
packageName = packageName.substring( 0, packageName.length() - 1 );
|
packageName = packageName.substring( 0, packageName.length() - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
annotatedPackages.add( packageName );
|
addPackageInternal( packageName );
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addPackageInternal(String packageName) {
|
||||||
|
if ( annotatedPackages == null ) {
|
||||||
|
annotatedPackages = new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
annotatedPackages.add( packageName );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read package-level metadata.
|
* Read package-level metadata.
|
||||||
*
|
*
|
||||||
|
@ -278,7 +294,7 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining)
|
* @return this (for method chaining)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addPackage(Package packageRef) {
|
public MetadataSources addPackage(Package packageRef) {
|
||||||
annotatedPackages.add( packageRef.getName() );
|
addPackageInternal( packageRef.getName() );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +313,9 @@ public class MetadataSources implements Serializable {
|
||||||
if ( entityClass == null ) {
|
if ( entityClass == null ) {
|
||||||
throw new IllegalArgumentException( "The specified class cannot be null" );
|
throw new IllegalArgumentException( "The specified class cannot be null" );
|
||||||
}
|
}
|
||||||
|
if ( LOG.isDebugEnabled() ) {
|
||||||
LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() );
|
LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() );
|
||||||
|
}
|
||||||
final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml";
|
final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml";
|
||||||
addResource( mappingResourceName );
|
addResource( mappingResourceName );
|
||||||
return this;
|
return this;
|
||||||
|
@ -311,7 +329,7 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining purposes)
|
* @return this (for method chaining purposes)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addResource(String name) {
|
public MetadataSources addResource(String name) {
|
||||||
xmlBindings.add( getXmlMappingBinderAccess().bind( name ) );
|
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( name ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +355,7 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining purposes)
|
* @return this (for method chaining purposes)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addFile(File file) {
|
public MetadataSources addFile(File file) {
|
||||||
xmlBindings.add( getXmlMappingBinderAccess().bind( file ) );
|
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( file ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +375,7 @@ public class MetadataSources implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCacheableFile(Origin origin, File file) {
|
private void addCacheableFile(Origin origin, File file) {
|
||||||
xmlBindings.add( new CacheableFileXmlSource( origin, file, false ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
|
getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, false ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -394,7 +412,7 @@ public class MetadataSources implements Serializable {
|
||||||
*/
|
*/
|
||||||
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException {
|
public MetadataSources addCacheableFileStrictly(File file) throws SerializationException, FileNotFoundException {
|
||||||
final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() );
|
final Origin origin = new Origin( SourceType.FILE, file.getAbsolutePath() );
|
||||||
xmlBindings.add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
|
getXmlBindingsForWrite().add( new CacheableFileXmlSource( origin, file, true ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +424,7 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining purposes)
|
* @return this (for method chaining purposes)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) {
|
public MetadataSources addInputStream(InputStreamAccess xmlInputStreamAccess) {
|
||||||
xmlBindings.add( getXmlMappingBinderAccess().bind( xmlInputStreamAccess ) );
|
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStreamAccess ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +436,7 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining purposes)
|
* @return this (for method chaining purposes)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addInputStream(InputStream xmlInputStream) {
|
public MetadataSources addInputStream(InputStream xmlInputStream) {
|
||||||
xmlBindings.add( getXmlMappingBinderAccess().bind( xmlInputStream ) );
|
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( xmlInputStream ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,7 +448,7 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining purposes)
|
* @return this (for method chaining purposes)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addURL(URL url) {
|
public MetadataSources addURL(URL url) {
|
||||||
xmlBindings.add( getXmlMappingBinderAccess().bind( url ) );
|
getXmlBindingsForWrite().add( getXmlMappingBinderAccess().bind( url ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +464,7 @@ public class MetadataSources implements Serializable {
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public MetadataSources addDocument(Document document) {
|
public MetadataSources addDocument(Document document) {
|
||||||
final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH );
|
final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH );
|
||||||
xmlBindings.add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
|
getXmlBindingsForWrite().add( new JaxpSourceXmlSource( origin, new DOMSource( document ) ).doBind( getXmlMappingBinderAccess().getMappingBinder() ) );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,17 +478,22 @@ public class MetadataSources implements Serializable {
|
||||||
* @return this (for method chaining purposes)
|
* @return this (for method chaining purposes)
|
||||||
*/
|
*/
|
||||||
public MetadataSources addJar(File jar) {
|
public MetadataSources addJar(File jar) {
|
||||||
|
if ( LOG.isDebugEnabled() ) {
|
||||||
LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() );
|
LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() );
|
||||||
|
}
|
||||||
final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() );
|
final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() );
|
||||||
try {
|
try {
|
||||||
JarFile jarFile = new JarFile( jar );
|
JarFile jarFile = new JarFile( jar );
|
||||||
|
final boolean TRACE = LOG.isTraceEnabled();
|
||||||
try {
|
try {
|
||||||
Enumeration jarEntries = jarFile.entries();
|
Enumeration jarEntries = jarFile.entries();
|
||||||
while ( jarEntries.hasMoreElements() ) {
|
while ( jarEntries.hasMoreElements() ) {
|
||||||
final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement();
|
final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement();
|
||||||
if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) {
|
if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) {
|
||||||
|
if ( TRACE ) {
|
||||||
LOG.tracef( "found mapping document : %s", zipEntry.getName() );
|
LOG.tracef( "found mapping document : %s", zipEntry.getName() );
|
||||||
xmlBindings.add(
|
}
|
||||||
|
getXmlBindingsForWrite().add(
|
||||||
new JarFileEntryXmlSource( origin, jarFile, zipEntry ).doBind( getXmlMappingBinderAccess().getMappingBinder() )
|
new JarFileEntryXmlSource( origin, jarFile, zipEntry ).doBind( getXmlMappingBinderAccess().getMappingBinder() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -490,6 +513,13 @@ public class MetadataSources implements Serializable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <Binding> List getXmlBindingsForWrite() {
|
||||||
|
if ( xmlBindings == null ) {
|
||||||
|
xmlBindings = new ArrayList<>();
|
||||||
|
}
|
||||||
|
return xmlBindings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all mapping documents from a directory tree.
|
* Read all mapping documents from a directory tree.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
|
|
@ -437,7 +437,7 @@ public class MapBinder extends CollectionBinder {
|
||||||
referencedEntityColumns = referencedProperty.getColumnIterator();
|
referencedEntityColumns = referencedProperty.getColumnIterator();
|
||||||
}
|
}
|
||||||
fromAndWhere = getFromAndWhereFormula(
|
fromAndWhere = getFromAndWhereFormula(
|
||||||
associatedClass.getTable().getName(),
|
associatedClass.getTable().getQualifiedTableName().toString(),
|
||||||
element.getColumnIterator(),
|
element.getColumnIterator(),
|
||||||
referencedEntityColumns
|
referencedEntityColumns
|
||||||
);
|
);
|
||||||
|
|
|
@ -332,6 +332,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext {
|
||||||
|| "getTransaction".equals( methodName )
|
|| "getTransaction".equals( methodName )
|
||||||
|| "isTransactionInProgress".equals( methodName )
|
|| "isTransactionInProgress".equals( methodName )
|
||||||
|| "setFlushMode".equals( methodName )
|
|| "setFlushMode".equals( methodName )
|
||||||
|
|| "setHibernateFlushMode".equals( methodName )
|
||||||
|| "getFactory".equals( methodName )
|
|| "getFactory".equals( methodName )
|
||||||
|| "getSessionFactory".equals( methodName )
|
|| "getSessionFactory".equals( methodName )
|
||||||
|| "getTenantIdentifier".equals( methodName ) ) {
|
|| "getTenantIdentifier".equals( methodName ) ) {
|
||||||
|
|
|
@ -260,15 +260,6 @@ public interface SharedSessionContractImplementor
|
||||||
Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable)
|
Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable)
|
||||||
throws HibernateException;
|
throws HibernateException;
|
||||||
|
|
||||||
default Object internalLoad(
|
|
||||||
String entityName,
|
|
||||||
Serializable id,
|
|
||||||
boolean eager,
|
|
||||||
boolean nullable,
|
|
||||||
Boolean unwrapProxy) throws HibernateException {
|
|
||||||
return internalLoad( entityName, id, eager, nullable );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an instance immediately. This method is only called when lazily initializing a proxy.
|
* Load an instance immediately. This method is only called when lazily initializing a proxy.
|
||||||
* Do not return the proxy.
|
* Do not return the proxy.
|
||||||
|
|
|
@ -299,7 +299,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
||||||
return createProxy( event, persister, keyToLoad, persistenceContext );
|
return createProxy( event, persister, keyToLoad, persistenceContext );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( !entityMetamodel.hasSubclasses() ) {
|
||||||
if ( keyToLoad.isBatchLoadable() ) {
|
if ( keyToLoad.isBatchLoadable() ) {
|
||||||
// Add a batch-fetch entry into the queue for this entity
|
// Add a batch-fetch entry into the queue for this entity
|
||||||
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
|
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
|
||||||
|
@ -309,6 +309,9 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
||||||
// create the (uninitialized) entity instance - has only id set
|
// create the (uninitialized) entity instance - has only id set
|
||||||
return persister.getBytecodeEnhancementMetadata().createEnhancedProxy( keyToLoad, true, session );
|
return persister.getBytecodeEnhancementMetadata().createEnhancedProxy( keyToLoad, true, session );
|
||||||
}
|
}
|
||||||
|
// If we get here, then the entity class has subclasses and there is no HibernateProxy factory.
|
||||||
|
// The entity will get loaded below.
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if ( persister.hasProxy() ) {
|
if ( persister.hasProxy() ) {
|
||||||
// look for a proxy
|
// look for a proxy
|
||||||
|
|
|
@ -975,18 +975,7 @@ public final class SessionImpl
|
||||||
String entityName,
|
String entityName,
|
||||||
Serializable id,
|
Serializable id,
|
||||||
boolean eager,
|
boolean eager,
|
||||||
boolean nullable) throws HibernateException {
|
boolean nullable) {
|
||||||
return internalLoad( entityName, id, eager, nullable, null );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Object internalLoad(
|
|
||||||
String entityName,
|
|
||||||
Serializable id,
|
|
||||||
boolean eager,
|
|
||||||
boolean nullable,
|
|
||||||
Boolean unwrapProxy) {
|
|
||||||
final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph();
|
final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph();
|
||||||
final GraphSemantic semantic = effectiveEntityGraph.getSemantic();
|
final GraphSemantic semantic = effectiveEntityGraph.getSemantic();
|
||||||
final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph();
|
final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph();
|
||||||
|
|
|
@ -298,13 +298,39 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata();
|
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata();
|
||||||
if ( allowBytecodeProxy && bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) {
|
if ( allowBytecodeProxy && bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) {
|
||||||
|
|
||||||
// we cannot use bytecode proxy for entities with subclasses
|
// if the entity defines a HibernateProxy factory, see if there is an
|
||||||
if ( !entityMetamodel.hasSubclasses() ) {
|
// existing proxy associated with the PC - and if so, use it
|
||||||
return bytecodeEnhancementMetadata.createEnhancedProxy( entityKey, false, this );
|
if ( persister.getEntityMetamodel().getTuplizer().getProxyFactory() != null ) {
|
||||||
|
final PersistenceContext persistenceContext = getPersistenceContext();
|
||||||
|
final Object proxy = persistenceContext.getProxy( entityKey );
|
||||||
|
|
||||||
|
if ( proxy != null ) {
|
||||||
|
if ( LOG.isTraceEnabled() ) {
|
||||||
|
LOG.trace( "Entity proxy found in session cache" );
|
||||||
}
|
}
|
||||||
|
if ( LOG.isDebugEnabled() && ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUnwrap() ) {
|
||||||
|
LOG.debug( "Ignoring NO_PROXY to honor laziness" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// we could not use bytecode proxy, check to see if we can use HibernateProxy
|
return persistenceContext.narrowProxy( proxy, persister, entityKey, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
// specialized handling for entities with subclasses with a HibernateProxy factory
|
||||||
|
if ( entityMetamodel.hasSubclasses() ) {
|
||||||
|
// entities with subclasses that define a ProxyFactory can create
|
||||||
|
// a HibernateProxy.
|
||||||
|
LOG.debugf( "Creating a HibernateProxy for to-one association with subclasses to honor laziness" );
|
||||||
|
return createProxy( entityKey );
|
||||||
|
}
|
||||||
|
return bytecodeEnhancementMetadata.createEnhancedProxy( entityKey, false, this );
|
||||||
|
}
|
||||||
|
else if ( !entityMetamodel.hasSubclasses() ) {
|
||||||
|
return bytecodeEnhancementMetadata.createEnhancedProxy( entityKey, false, this );
|
||||||
|
}
|
||||||
|
// If we get here, then the entity class has subclasses and there is no HibernateProxy factory.
|
||||||
|
// The entity will get loaded below.
|
||||||
|
}
|
||||||
|
else {
|
||||||
if ( persister.hasProxy() ) {
|
if ( persister.hasProxy() ) {
|
||||||
final PersistenceContext persistenceContext = getPersistenceContext();
|
final PersistenceContext persistenceContext = getPersistenceContext();
|
||||||
final Object existingProxy = persistenceContext.getProxy( entityKey );
|
final Object existingProxy = persistenceContext.getProxy( entityKey );
|
||||||
|
@ -312,9 +338,8 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
return persistenceContext.narrowProxy( existingProxy, persister, entityKey, null );
|
return persistenceContext.narrowProxy( existingProxy, persister, entityKey, null );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final Object proxy = persister.createProxy( id, this );
|
return createProxy( entityKey );
|
||||||
persistenceContext.addProxy( entityKey, proxy );
|
}
|
||||||
return proxy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,6 +348,12 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
return get( entityName, id );
|
return get( entityName, id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object createProxy(EntityKey entityKey) {
|
||||||
|
final Object proxy = entityKey.getPersister().createProxy( entityKey.getIdentifier(), this );
|
||||||
|
getPersistenceContext().addProxy( entityKey, proxy );
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAutoCloseSessionEnabled() {
|
public boolean isAutoCloseSessionEnabled() {
|
||||||
return getFactory().getSessionFactoryOptions().isAutoCloseSessionEnabled();
|
return getFactory().getSessionFactoryOptions().isAutoCloseSessionEnabled();
|
||||||
|
|
|
@ -1733,6 +1733,7 @@ public abstract class Loader {
|
||||||
// see if the entity defines reference caching, and if so use the cached reference (if one).
|
// see if the entity defines reference caching, and if so use the cached reference (if one).
|
||||||
if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) {
|
if ( session.getCacheMode().isGetEnabled() && persister.canUseReferenceCacheEntries() ) {
|
||||||
final EntityDataAccess cache = persister.getCacheAccessStrategy();
|
final EntityDataAccess cache = persister.getCacheAccessStrategy();
|
||||||
|
if ( cache != null ) {
|
||||||
final Object ck = cache.generateCacheKey(
|
final Object ck = cache.generateCacheKey(
|
||||||
key.getIdentifier(),
|
key.getIdentifier(),
|
||||||
persister,
|
persister,
|
||||||
|
@ -1741,10 +1742,14 @@ public abstract class Loader {
|
||||||
);
|
);
|
||||||
final Object cachedEntry = CacheHelper.fromSharedCache( session, ck, cache );
|
final Object cachedEntry = CacheHelper.fromSharedCache( session, ck, cache );
|
||||||
if ( cachedEntry != null ) {
|
if ( cachedEntry != null ) {
|
||||||
CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure( cachedEntry, factory );
|
CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure(
|
||||||
|
cachedEntry,
|
||||||
|
factory
|
||||||
|
);
|
||||||
return ( (ReferenceCacheEntryImpl) entry ).getReference();
|
return ( (ReferenceCacheEntryImpl) entry ).getReference();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final Object object;
|
final Object object;
|
||||||
if ( optionalObjectKey != null && key.equals( optionalObjectKey ) ) {
|
if ( optionalObjectKey != null && key.equals( optionalObjectKey ) ) {
|
||||||
|
|
|
@ -655,8 +655,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
getAssociatedEntityName(),
|
getAssociatedEntityName(),
|
||||||
id,
|
id,
|
||||||
eager,
|
eager,
|
||||||
isNullable(),
|
isNullable()
|
||||||
unwrapProxy
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( proxyOrEntity instanceof HibernateProxy ) {
|
if ( proxyOrEntity instanceof HibernateProxy ) {
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* 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.bytecode.enhancement.lazy;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.ScrollMode;
|
||||||
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.StatelessSession;
|
||||||
|
import org.hibernate.annotations.LazyToOne;
|
||||||
|
import org.hibernate.annotations.LazyToOneOption;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
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 org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
public class QueryScrollingWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( EmployeeParent.class );
|
||||||
|
sources.addAnnotatedClass( Employee.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScrollableWithStatelessSession() {
|
||||||
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
ScrollableResults scrollableResults = null;
|
||||||
|
final StatelessSession statelessSession = sessionFactory().openStatelessSession();
|
||||||
|
|
||||||
|
try {
|
||||||
|
statelessSession.beginTransaction();
|
||||||
|
Query<Employee> query = statelessSession.createQuery(
|
||||||
|
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( getDialect() instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
final Employee employee = (Employee) scrollableResults.get( 0 );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
|
||||||
|
if ( "ENG1".equals( employee.getDept() ) ) {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 2 ) );
|
||||||
|
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( false ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statelessSession.getTransaction().commit();
|
||||||
|
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( scrollableResults != null ) {
|
||||||
|
scrollableResults.close();
|
||||||
|
}
|
||||||
|
if ( statelessSession.getTransaction().isActive() ) {
|
||||||
|
statelessSession.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
statelessSession.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScrollableWithSession() {
|
||||||
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
ScrollableResults scrollableResults = null;
|
||||||
|
final Session session = sessionFactory().openSession();
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.beginTransaction();
|
||||||
|
Query<Employee> query = session.createQuery(
|
||||||
|
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( getDialect() instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
final Employee employee = (Employee) scrollableResults.get( 0 );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
|
||||||
|
if ( "ENG1".equals( employee.getDept() ) ) {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 2 ) );
|
||||||
|
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( false ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session.getTransaction().commit();
|
||||||
|
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( scrollableResults != null ) {
|
||||||
|
scrollableResults.close();
|
||||||
|
}
|
||||||
|
if ( session.getTransaction().isActive() ) {
|
||||||
|
session.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepareTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Employee e1 = new Employee( "ENG1" );
|
||||||
|
Employee e2 = new Employee( "ENG2" );
|
||||||
|
OtherEntity other1 = new OtherEntity( "test1" );
|
||||||
|
OtherEntity other2 = new OtherEntity( "test2" );
|
||||||
|
e1.getOtherEntities().add( other1 );
|
||||||
|
e1.getOtherEntities().add( other2 );
|
||||||
|
e1.getParentOtherEntities().add( other1 );
|
||||||
|
e1.getParentOtherEntities().add( other2 );
|
||||||
|
other1.employee = e1;
|
||||||
|
other2.employee = e1;
|
||||||
|
other1.employeeParent = e1;
|
||||||
|
other2.employeeParent = e2;
|
||||||
|
session.persist( other1 );
|
||||||
|
session.persist( other2 );
|
||||||
|
session.persist( e1 );
|
||||||
|
session.persist( e2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from EmployeeParent" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "EmployeeParent")
|
||||||
|
@Table(name = "EmployeeParent")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
public static abstract class EmployeeParent {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String dept;
|
||||||
|
|
||||||
|
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY)
|
||||||
|
protected Set<OtherEntity> parentOtherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public Set<OtherEntity> getParentOtherEntities() {
|
||||||
|
if ( parentOtherEntities == null ) {
|
||||||
|
parentOtherEntities = new LinkedHashSet();
|
||||||
|
}
|
||||||
|
return parentOtherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<OtherEntity> pParentOtherEntites) {
|
||||||
|
parentOtherEntities = pParentOtherEntites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDept() {
|
||||||
|
return dept;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDept(String dept) {
|
||||||
|
this.dept = dept;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
@Table(name = "Employee")
|
||||||
|
public static class Employee extends EmployeeParent {
|
||||||
|
|
||||||
|
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY)
|
||||||
|
protected Set<OtherEntity> otherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public Employee(String dept) {
|
||||||
|
this();
|
||||||
|
setDept( dept );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Employee() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<OtherEntity> getOtherEntities() {
|
||||||
|
if ( otherEntities == null ) {
|
||||||
|
otherEntities = new LinkedHashSet();
|
||||||
|
}
|
||||||
|
return otherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<OtherEntity> pOtherEntites) {
|
||||||
|
otherEntities = pOtherEntites;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
@JoinColumn(name = "Employee_Id")
|
||||||
|
protected Employee employee = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
@JoinColumn(name = "EmployeeParent_Id")
|
||||||
|
protected EmployeeParent employeeParent = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,476 @@
|
||||||
|
/*
|
||||||
|
* 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.bytecode.enhancement.lazy.proxy;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.EntityMode;
|
||||||
|
import org.hibernate.EntityNameResolver;
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.annotations.LazyToOne;
|
||||||
|
import org.hibernate.annotations.LazyToOneOption;
|
||||||
|
import org.hibernate.annotations.Tuplizer;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.property.access.spi.Getter;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
import org.hibernate.proxy.ProxyFactory;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
|
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||||
|
import org.hibernate.tuple.entity.PojoEntityTuplizer;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-13640" )
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
public class LazyToOnesNoProxyFactoryWithSubclassesStatefulTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( Animal.class );
|
||||||
|
sources.addAnnotatedClass( Primate.class );
|
||||||
|
sources.addAnnotatedClass( Human.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewEnhancedProxyAssociation() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
|
||||||
|
session.persist( human );
|
||||||
|
session.persist( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingInitializedAssociationLeafSubclass() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.animal = human;
|
||||||
|
otherEntity.primate = human;
|
||||||
|
otherEntity.human = human;
|
||||||
|
session.persist( human );
|
||||||
|
session.persist( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
inSession(
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.primate ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertSame( otherEntity.human, otherEntity.animal );
|
||||||
|
assertSame( otherEntity.human, otherEntity.primate );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
otherEntity.otherHuman = human;
|
||||||
|
session.persist( human );
|
||||||
|
session.persist( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertNull( otherEntity.animal );
|
||||||
|
assertNull( otherEntity.primate );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "otherHuman" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.otherHuman ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.otherHuman ) );
|
||||||
|
assertSame( otherEntity.human, otherEntity.otherHuman );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Human" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Primate" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Animal" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Animal")
|
||||||
|
@Table(name = "Animal")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
@Tuplizer(impl=NoProxyFactoryPojoEntityTuplizer.class)
|
||||||
|
public static abstract class Animal {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Primate")
|
||||||
|
@Table(name = "Primate")
|
||||||
|
public static class Primate extends Animal {
|
||||||
|
|
||||||
|
public Primate(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Primate() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Human")
|
||||||
|
@Table(name = "Human")
|
||||||
|
public static class Human extends Primate {
|
||||||
|
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
public Human(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Human() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSex(String sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Animal animal = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Primate primate = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Human human = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Human otherHuman = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Human getHuman() {
|
||||||
|
return human;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHuman(Human human) {
|
||||||
|
this.human = human;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoProxyFactoryPojoEntityTuplizer implements EntityTuplizer {
|
||||||
|
|
||||||
|
private final PojoEntityTuplizer pojoEntityTuplizer;
|
||||||
|
|
||||||
|
public NoProxyFactoryPojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
|
||||||
|
pojoEntityTuplizer = new PojoEntityTuplizer( entityMetamodel, mappedEntity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityMode getEntityMode() {
|
||||||
|
return pojoEntityTuplizer.getEntityMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate(Serializable id) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.instantiate( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate(Serializable id, SharedSessionContractImplementor session) {
|
||||||
|
return pojoEntityTuplizer.instantiate( id, session );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable getIdentifier(Object entity) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getIdentifier( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
return pojoEntityTuplizer.getIdentifier( entity, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIdentifier(Object entity, Serializable id) throws HibernateException {
|
||||||
|
pojoEntityTuplizer.setIdentifier( entity, id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIdentifier(Object entity, Serializable id, SharedSessionContractImplementor session) {
|
||||||
|
pojoEntityTuplizer.setIdentifier( entity, id, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
|
||||||
|
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetIdentifier(
|
||||||
|
Object entity,
|
||||||
|
Serializable currentId,
|
||||||
|
Object currentVersion,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getVersion(Object entity) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getVersion( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValue(Object entity, int i, Object value) throws HibernateException {
|
||||||
|
pojoEntityTuplizer. setPropertyValue( entity, i, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException {
|
||||||
|
pojoEntityTuplizer.setPropertyValue( entity, propertyName, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getPropertyValuesToInsert(
|
||||||
|
Object entity,
|
||||||
|
Map mergeMap,
|
||||||
|
SharedSessionContractImplementor session) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getPropertyValuesToInsert( entity, mergeMap, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPropertyValue(Object entity, String propertyName) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getPropertyValue( entity, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
pojoEntityTuplizer.afterInitialize( entity, session );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasProxy() {
|
||||||
|
return pojoEntityTuplizer.hasProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object createProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.createProxy( id, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLifecycleImplementor() {
|
||||||
|
return pojoEntityTuplizer.isLifecycleImplementor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getConcreteProxyClass() {
|
||||||
|
return pojoEntityTuplizer.getConcreteProxyClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityNameResolver[] getEntityNameResolvers() {
|
||||||
|
return pojoEntityTuplizer.getEntityNameResolvers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String determineConcreteSubclassEntityName(
|
||||||
|
Object entityInstance, SessionFactoryImplementor factory) {
|
||||||
|
return pojoEntityTuplizer.determineConcreteSubclassEntityName( entityInstance, factory );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Getter getIdentifierGetter() {
|
||||||
|
return pojoEntityTuplizer.getIdentifierGetter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Getter getVersionGetter() {
|
||||||
|
return pojoEntityTuplizer.getVersionGetter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProxyFactory getProxyFactory() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getPropertyValues(Object entity) {
|
||||||
|
return pojoEntityTuplizer.getPropertyValues( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValues(Object entity, Object[] values) {
|
||||||
|
pojoEntityTuplizer.setPropertyValues( entity, values );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPropertyValue(Object entity, int i) {
|
||||||
|
return pojoEntityTuplizer.getPropertyValue( entity, i );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate() {
|
||||||
|
return pojoEntityTuplizer.instantiate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInstance(Object object) {
|
||||||
|
return pojoEntityTuplizer.isInstance( object );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getMappedClass() {
|
||||||
|
return pojoEntityTuplizer.getMappedClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Getter getGetter(int i) {
|
||||||
|
return pojoEntityTuplizer.getGetter( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,476 @@
|
||||||
|
/*
|
||||||
|
* 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.bytecode.enhancement.lazy.proxy;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.EntityMode;
|
||||||
|
import org.hibernate.EntityNameResolver;
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.annotations.LazyToOne;
|
||||||
|
import org.hibernate.annotations.LazyToOneOption;
|
||||||
|
import org.hibernate.annotations.Tuplizer;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.property.access.spi.Getter;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
import org.hibernate.proxy.ProxyFactory;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
|
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||||
|
import org.hibernate.tuple.entity.PojoEntityTuplizer;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-13640" )
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
public class LazyToOnesNoProxyFactoryWithSubclassesStatelessTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( Animal.class );
|
||||||
|
sources.addAnnotatedClass( Primate.class );
|
||||||
|
sources.addAnnotatedClass( Human.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewEnhancedProxyAssociation() {
|
||||||
|
inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingInitializedAssociationLeafSubclass() {
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.animal = human;
|
||||||
|
otherEntity.primate = human;
|
||||||
|
otherEntity.human = human;
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.primate ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertSame( otherEntity.human, otherEntity.animal );
|
||||||
|
assertSame( otherEntity.human, otherEntity.primate );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
otherEntity.otherHuman = human;
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertNull( otherEntity.animal );
|
||||||
|
assertNull( otherEntity.primate );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "otherHuman" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.otherHuman ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.otherHuman ) );
|
||||||
|
assertSame( otherEntity.human, otherEntity.otherHuman );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Human" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Primate" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Animal" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Animal")
|
||||||
|
@Table(name = "Animal")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
@Tuplizer(impl=NoProxyFactoryPojoEntityTuplizer.class)
|
||||||
|
public static abstract class Animal {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Primate")
|
||||||
|
@Table(name = "Primate")
|
||||||
|
public static class Primate extends Animal {
|
||||||
|
|
||||||
|
public Primate(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Primate() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Human")
|
||||||
|
@Table(name = "Human")
|
||||||
|
public static class Human extends Primate {
|
||||||
|
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
public Human(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Human() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSex(String sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Animal animal = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Primate primate = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Human human = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Human otherHuman = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Human getHuman() {
|
||||||
|
return human;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHuman(Human human) {
|
||||||
|
this.human = human;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoProxyFactoryPojoEntityTuplizer implements EntityTuplizer {
|
||||||
|
|
||||||
|
private final PojoEntityTuplizer pojoEntityTuplizer;
|
||||||
|
|
||||||
|
public NoProxyFactoryPojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
|
||||||
|
pojoEntityTuplizer = new PojoEntityTuplizer( entityMetamodel, mappedEntity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityMode getEntityMode() {
|
||||||
|
return pojoEntityTuplizer.getEntityMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate(Serializable id) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.instantiate( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate(Serializable id, SharedSessionContractImplementor session) {
|
||||||
|
return pojoEntityTuplizer.instantiate( id, session );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable getIdentifier(Object entity) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getIdentifier( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
return pojoEntityTuplizer.getIdentifier( entity, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIdentifier(Object entity, Serializable id) throws HibernateException {
|
||||||
|
pojoEntityTuplizer.setIdentifier( entity, id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIdentifier(Object entity, Serializable id, SharedSessionContractImplementor session) {
|
||||||
|
pojoEntityTuplizer.setIdentifier( entity, id, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
|
||||||
|
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetIdentifier(
|
||||||
|
Object entity,
|
||||||
|
Serializable currentId,
|
||||||
|
Object currentVersion,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
pojoEntityTuplizer.resetIdentifier( entity, currentId, currentVersion, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getVersion(Object entity) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getVersion( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValue(Object entity, int i, Object value) throws HibernateException {
|
||||||
|
pojoEntityTuplizer. setPropertyValue( entity, i, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException {
|
||||||
|
pojoEntityTuplizer.setPropertyValue( entity, propertyName, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getPropertyValuesToInsert(
|
||||||
|
Object entity,
|
||||||
|
Map mergeMap,
|
||||||
|
SharedSessionContractImplementor session) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getPropertyValuesToInsert( entity, mergeMap, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPropertyValue(Object entity, String propertyName) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.getPropertyValue( entity, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
pojoEntityTuplizer.afterInitialize( entity, session );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasProxy() {
|
||||||
|
return pojoEntityTuplizer.hasProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object createProxy(Serializable id, SharedSessionContractImplementor session) throws HibernateException {
|
||||||
|
return pojoEntityTuplizer.createProxy( id, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLifecycleImplementor() {
|
||||||
|
return pojoEntityTuplizer.isLifecycleImplementor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getConcreteProxyClass() {
|
||||||
|
return pojoEntityTuplizer.getConcreteProxyClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityNameResolver[] getEntityNameResolvers() {
|
||||||
|
return pojoEntityTuplizer.getEntityNameResolvers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String determineConcreteSubclassEntityName(
|
||||||
|
Object entityInstance, SessionFactoryImplementor factory) {
|
||||||
|
return pojoEntityTuplizer.determineConcreteSubclassEntityName( entityInstance, factory );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Getter getIdentifierGetter() {
|
||||||
|
return pojoEntityTuplizer.getIdentifierGetter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Getter getVersionGetter() {
|
||||||
|
return pojoEntityTuplizer.getVersionGetter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProxyFactory getProxyFactory() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getPropertyValues(Object entity) {
|
||||||
|
return pojoEntityTuplizer.getPropertyValues( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValues(Object entity, Object[] values) {
|
||||||
|
pojoEntityTuplizer.setPropertyValues( entity, values );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPropertyValue(Object entity, int i) {
|
||||||
|
return pojoEntityTuplizer.getPropertyValue( entity, i );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate() {
|
||||||
|
return pojoEntityTuplizer.instantiate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInstance(Object object) {
|
||||||
|
return pojoEntityTuplizer.isInstance( object );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getMappedClass() {
|
||||||
|
return pojoEntityTuplizer.getMappedClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Getter getGetter(int i) {
|
||||||
|
return pojoEntityTuplizer.getGetter( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,865 @@
|
||||||
|
/*
|
||||||
|
* 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.bytecode.enhancement.lazy.proxy;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
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.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||||
|
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 org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-13640" )
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class )
|
||||||
|
@EnhancementOptions(lazyLoading = true)
|
||||||
|
public class LazyToOnesProxyMergeWithSubclassesTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( Animal.class );
|
||||||
|
sources.addAnnotatedClass( Primate.class );
|
||||||
|
sources.addAnnotatedClass( Human.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergeUpdatedHibernateProxy() {
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity withInitializedHibernateProxy = doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
otherEntity.getHuman().getSex();
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
return otherEntity;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated HibernateProxy to updated HibernateProxy
|
||||||
|
|
||||||
|
withInitializedHibernateProxy.getHuman().setAge( 2 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
otherEntity.getHuman().setAge( 3 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
|
||||||
|
.getHibernateLazyInitializer()
|
||||||
|
.getImplementation();
|
||||||
|
|
||||||
|
session.merge( withInitializedHibernateProxy );
|
||||||
|
// TODO: Reference to associated HibernateProxy is changed
|
||||||
|
// to the HibernateProxy's implementation.
|
||||||
|
assertSame( humanImpl, otherEntity.getHuman() );
|
||||||
|
assertEquals( 2, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 2 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated HibernateProxy to updated enhanced entity
|
||||||
|
|
||||||
|
withInitializedHibernateProxy.getHuman().setAge( 4 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
human.setAge( 5 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
session.merge( withInitializedHibernateProxy );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertEquals( 4, human.getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 4 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated HibernateProxy to uninitialized HibernateProxy
|
||||||
|
|
||||||
|
withInitializedHibernateProxy.getHuman().setAge( 6 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
final Human humanHibernateProxy = otherEntity.getHuman();
|
||||||
|
|
||||||
|
session.merge( withInitializedHibernateProxy );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
// TODO: Reference to associated HibernateProxy is changed
|
||||||
|
// reference to the HibernateProxy's implementation.
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
assertSame(
|
||||||
|
otherEntity.getHuman(),
|
||||||
|
( (HibernateProxy) humanHibernateProxy ).getHibernateLazyInitializer().getImplementation()
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 6, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 6 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated HibernateProxy To uninitialized enhanced proxy
|
||||||
|
|
||||||
|
withInitializedHibernateProxy.getHuman().setAge( 7 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
|
session.merge( withInitializedHibernateProxy );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertTrue( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
|
assertEquals( 7, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergeUpdatedEnhancedProxy() {
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity withInitializedEnhancedProxy = doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
otherEntity.getHuman().getSex();
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
return otherEntity;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated enhanced proxy to updated HibernateProxy
|
||||||
|
|
||||||
|
withInitializedEnhancedProxy.getHuman().setAge( 2 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
otherEntity.getHuman().setAge( 3 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
|
||||||
|
.getHibernateLazyInitializer()
|
||||||
|
.getImplementation();
|
||||||
|
|
||||||
|
session.merge( withInitializedEnhancedProxy );
|
||||||
|
// TODO: Reference to HibernateProxy is changed
|
||||||
|
// to the HibernateProxy's implementation.
|
||||||
|
assertSame( humanImpl, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 2, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 2 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated enhanced proxy to updated enhanced proxy
|
||||||
|
|
||||||
|
withInitializedEnhancedProxy.getHuman().setAge( 4 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
human.setAge( 5 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
session.merge( withInitializedEnhancedProxy );
|
||||||
|
assertEquals( 4, human.getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 4 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated enhanced proxy to uninitialized HibernateProxy
|
||||||
|
|
||||||
|
withInitializedEnhancedProxy.getHuman().setAge( 6 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
session.merge( withInitializedEnhancedProxy );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
// TODO: Reference in managed entity gets changed from a HibernateProxy
|
||||||
|
// to an initialized entity. This happens without enhancement as well.
|
||||||
|
//assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 6, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 6 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge updated enhanced proxy to uninitialized enhanced proxy
|
||||||
|
|
||||||
|
withInitializedEnhancedProxy.getHuman().setAge( 7 );
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
|
session.merge( withInitializedEnhancedProxy );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertTrue( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
|
assertEquals( 7, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergeUninitializedHibernateProxy() {
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity withUninitializedHibernateProxy = doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
return otherEntity;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized HibernateProxy to updated HibernateProxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
otherEntity.getHuman().setAge( 3 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
|
||||||
|
.getHibernateLazyInitializer()
|
||||||
|
.getImplementation();
|
||||||
|
|
||||||
|
session.merge( withUninitializedHibernateProxy );
|
||||||
|
//assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
// TODO: Reference to HibernateProxy is changed
|
||||||
|
// to the HibernateProxy's implementation.
|
||||||
|
assertSame( humanImpl, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 3, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 3 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized HibernateProxy to updated enhanced proxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
human.setAge( 5 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
session.merge( withUninitializedHibernateProxy );
|
||||||
|
assertEquals( 5, human.getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 5 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized HibernateProxy to uninitialized HibernateProxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
session.merge( withUninitializedHibernateProxy );
|
||||||
|
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 5 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized HibernateProxy to uninitialized enhanced proxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
|
session.merge( withUninitializedHibernateProxy );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testmergeUninitializedEnhancedProxy() {
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity withUninitializedEnhancedProxy = doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
return otherEntity;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 1 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized enhanced proxy to updated HibernateProxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
otherEntity.getHuman().setAge( 3 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final Human humanImpl = (Human) ( (HibernateProxy) otherEntity.getHuman() )
|
||||||
|
.getHibernateLazyInitializer()
|
||||||
|
.getImplementation();
|
||||||
|
|
||||||
|
session.merge( withUninitializedEnhancedProxy );
|
||||||
|
// TODO: Reference to HibernateProxy is changed
|
||||||
|
// to the HibernateProxy's implementation.
|
||||||
|
assertSame( humanImpl, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 3, otherEntity.getHuman().getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 3 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized enhanced proxy to updated enhanced entity
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
human.setAge( 5 );
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
session.merge( withUninitializedEnhancedProxy );
|
||||||
|
assertEquals( 5, human.getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 3, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 5 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized enhanced proxy to uninitialized HibernateProxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
session.merge( withUninitializedEnhancedProxy );
|
||||||
|
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.getHuman() ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 5 );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
// merge uninitialized enhanced proxy to uninitialized enhanced proxy
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( human ) );
|
||||||
|
assertEquals( 0, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
|
session.merge( withUninitializedEnhancedProxy );
|
||||||
|
assertSame( human, otherEntity.getHuman() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
checkAgeInNewSession( 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAgeInNewSession(int expectedAge) {
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory,
|
||||||
|
session -> {
|
||||||
|
final Human human = session.get( Human.class, "A Human" );
|
||||||
|
assertEquals( expectedAge, human.getAge() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.animal = human;
|
||||||
|
otherEntity.primate = human;
|
||||||
|
otherEntity.human = human;
|
||||||
|
otherEntity.human.setAge( 1 );
|
||||||
|
|
||||||
|
session.persist( human );
|
||||||
|
session.persist( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Human" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Primate" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Animal" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Animal")
|
||||||
|
@Table(name = "Animal")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
public static abstract class Animal {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Primate")
|
||||||
|
@Table(name = "Primate")
|
||||||
|
public static class Primate extends Animal {
|
||||||
|
|
||||||
|
public Primate(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Primate() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Human")
|
||||||
|
@Table(name = "Human")
|
||||||
|
public static class Human extends Primate {
|
||||||
|
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
public Human(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Human() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSex(String sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Animal animal = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Primate primate = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Human human = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Human getHuman() {
|
||||||
|
return human;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHuman(Human human) {
|
||||||
|
this.human = human;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,332 @@
|
||||||
|
/*
|
||||||
|
* 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.bytecode.enhancement.lazy.proxy;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
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.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
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.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-13640" )
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
public class LazyToOnesProxyWithSubclassesStatelessTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( Animal.class );
|
||||||
|
sources.addAnnotatedClass( Primate.class );
|
||||||
|
sources.addAnnotatedClass( Human.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewHibernateProxyAssociation() {
|
||||||
|
inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.animal = human;
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewEnhancedProxyAssociation() {
|
||||||
|
inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingProxyAssociation() {
|
||||||
|
inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.animal = human;
|
||||||
|
otherEntity.primate = human;
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingHibernateProxyAssociationLeafSubclass() {
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.animal = human;
|
||||||
|
otherEntity.primate = human;
|
||||||
|
otherEntity.human = human;
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
session.insert( human );
|
||||||
|
session.insert( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = (OtherEntity) session.get( OtherEntity.class, "test1" );
|
||||||
|
assertNull( otherEntity.animal );
|
||||||
|
assertNull( otherEntity.primate );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Human" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Primate" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Animal" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Animal")
|
||||||
|
@Table(name = "Animal")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
public static abstract class Animal {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Primate")
|
||||||
|
@Table(name = "Primate")
|
||||||
|
public static class Primate extends Animal {
|
||||||
|
|
||||||
|
public Primate(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Primate() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Human")
|
||||||
|
@Table(name = "Human")
|
||||||
|
public static class Human extends Primate {
|
||||||
|
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
public Human(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Human() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSex() {
|
||||||
|
return sex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSex(String sex) {
|
||||||
|
this.sex = sex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Animal animal = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Primate primate = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Human human = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Human getHuman() {
|
||||||
|
return human;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHuman(Human human) {
|
||||||
|
this.human = human;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,8 +31,10 @@ import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,7 +156,7 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExistingProxyAssociationLeafSubclass() {
|
public void testExistingHibernateProxyAssociationLeafSubclass() {
|
||||||
inTransaction(
|
inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Human human = new Human( "A Human" );
|
Human human = new Human( "A Human" );
|
||||||
|
@ -167,11 +169,12 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
inSession(
|
|
||||||
session -> {
|
|
||||||
final Statistics stats = sessionFactory().getStatistics();
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
stats.clear();
|
stats.clear();
|
||||||
|
|
||||||
|
inSession(
|
||||||
|
session -> {
|
||||||
|
|
||||||
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
@ -181,18 +184,101 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||||
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
// TODO: Should otherEntity.human be a narrowed HibernateProxy or
|
|
||||||
// an uninitialized non-HibernateProxy proxy?
|
|
||||||
assertEquals( 1, stats.getPrepareStatementCount() );
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
Human human = otherEntity.getHuman();
|
// Make sure human can still get loaded and not initialized.
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
|
||||||
human.getName();
|
human.getName();
|
||||||
assertEquals( 1, stats.getPrepareStatementCount() );
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
|
||||||
human.getSex();
|
human.getSex();
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isInitialized( human ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
assertEquals( 2, stats.getPrepareStatementCount() );
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
inSession(
|
||||||
|
session -> {
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "animal" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.animal ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.animal ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "primate" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.primate ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.primate ) );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
// Make sure human can still get loaded
|
||||||
|
final Human human = session.get( Human.class, "A Human" );
|
||||||
|
assertTrue( !HibernateProxy.class.isInstance( human ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( human ) );
|
||||||
|
assertTrue( HibernateProxy.class.isInstance( otherEntity.getHuman() ) );
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExistingEnhancedProxyAssociationLeafSubclassOnly() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Human human = new Human( "A Human" );
|
||||||
|
OtherEntity otherEntity = new OtherEntity( "test1" );
|
||||||
|
otherEntity.human = human;
|
||||||
|
session.persist( human );
|
||||||
|
session.persist( otherEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
final Statistics stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
|
||||||
|
final OtherEntity otherEntity = session.get( OtherEntity.class, "test1" );
|
||||||
|
assertNull( otherEntity.animal );
|
||||||
|
assertNull( otherEntity.primate );
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( otherEntity, "human" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
// Make sure human can still get loaded and not initialized.
|
||||||
|
final Human human = session.getReference( Human.class, "A Human" );
|
||||||
|
assertFalse( Hibernate.isInitialized( human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
|
||||||
|
human.getName();
|
||||||
|
assertEquals( 1, stats.getPrepareStatementCount() );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
|
||||||
|
human.getSex();
|
||||||
|
assertTrue( Hibernate.isInitialized( otherEntity.human ) );
|
||||||
|
assertFalse( HibernateProxy.class.isInstance( otherEntity.human ) );
|
||||||
|
assertEquals( 2, stats.getPrepareStatementCount() );
|
||||||
|
|
||||||
|
return otherEntity;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -215,6 +301,8 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
@Id
|
@Id
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -223,6 +311,13 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = "Primate")
|
@Entity(name = "Primate")
|
||||||
|
@ -272,15 +367,15 @@ public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunction
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
protected Animal animal = null;
|
private Animal animal = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
protected Primate primate = null;
|
private Primate primate = null;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@LazyToOne(LazyToOneOption.NO_PROXY)
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
protected Human human = null;
|
private Human human = null;
|
||||||
|
|
||||||
protected OtherEntity() {
|
protected OtherEntity() {
|
||||||
// this form used by Hibernate
|
// this form used by Hibernate
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.junit.runner.RunWith;
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,7 +156,8 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
|
||||||
session -> {
|
session -> {
|
||||||
final Animal animal = session.load( Animal.class, "animal" );
|
final Animal animal = session.load( Animal.class, "animal" );
|
||||||
assertFalse( Hibernate.isInitialized( animal ) );
|
assertFalse( Hibernate.isInitialized( animal ) );
|
||||||
session.merge( animalInitialized );
|
final Animal animalMerged = (Animal) session.merge( animalInitialized );
|
||||||
|
assertSame( animal, animalMerged );
|
||||||
assertTrue( Hibernate.isInitialized( animal ) );
|
assertTrue( Hibernate.isInitialized( animal ) );
|
||||||
assertEquals( 4, animal.getAge() );
|
assertEquals( 4, animal.getAge() );
|
||||||
assertEquals( "other", animal.getSex() );
|
assertEquals( "other", animal.getSex() );
|
||||||
|
@ -204,7 +206,8 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
|
||||||
assertTrue( Hibernate.isInitialized( animal ) );
|
assertTrue( Hibernate.isInitialized( animal ) );
|
||||||
animal.setAge( 5 );
|
animal.setAge( 5 );
|
||||||
animal.setSex( "male" );
|
animal.setSex( "male" );
|
||||||
session.merge( animalInitialized );
|
final Animal animalMerged = (Animal) session.merge( animalInitialized );
|
||||||
|
assertSame( animal, animalMerged );
|
||||||
assertEquals( 4, animal.getAge() );
|
assertEquals( 4, animal.getAge() );
|
||||||
assertEquals( "other", animal.getSex() );
|
assertEquals( "other", animal.getSex() );
|
||||||
}
|
}
|
||||||
|
@ -245,7 +248,8 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
|
||||||
session -> {
|
session -> {
|
||||||
final Animal animal = session.load( Animal.class, "animal" );
|
final Animal animal = session.load( Animal.class, "animal" );
|
||||||
assertFalse( Hibernate.isInitialized( animal ) );
|
assertFalse( Hibernate.isInitialized( animal ) );
|
||||||
session.merge( animalUninitialized );
|
final Animal animalMerged = (Animal) session.merge( animalUninitialized );
|
||||||
|
assertSame( animal, animalMerged );
|
||||||
assertFalse( Hibernate.isInitialized( animal ) );
|
assertFalse( Hibernate.isInitialized( animal ) );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -283,11 +287,13 @@ public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTes
|
||||||
|
|
||||||
inTransaction(
|
inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
final Animal animal = session.get( Animal.class, "animal" );
|
final Animal animal = session.load( Animal.class, "animal" );
|
||||||
assertTrue( Hibernate.isInitialized( animal ) );
|
assertFalse( Hibernate.isInitialized( animal ) );
|
||||||
animal.setSex( "other" );
|
animal.setSex( "other" );
|
||||||
|
assertTrue( Hibernate.isInitialized( animal ) );
|
||||||
animal.setAge( 4 );
|
animal.setAge( 4 );
|
||||||
session.merge( animalUninitialized );
|
final Animal animalMerged = (Animal) session.merge( animalUninitialized );
|
||||||
|
assertSame( animal, animalMerged );
|
||||||
assertTrue( Hibernate.isInitialized( animal ) );
|
assertTrue( Hibernate.isInitialized( animal ) );
|
||||||
assertEquals( "other", animal.getSex() );
|
assertEquals( "other", animal.getSex() );
|
||||||
assertEquals( 4, animal.getAge() );
|
assertEquals( 4, animal.getAge() );
|
||||||
|
|
|
@ -0,0 +1,327 @@
|
||||||
|
/*
|
||||||
|
* 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.bytecode.enhancement.lazy.proxy;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.ScrollMode;
|
||||||
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.StatelessSession;
|
||||||
|
import org.hibernate.annotations.LazyToOne;
|
||||||
|
import org.hibernate.annotations.LazyToOneOption;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
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 org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
public class QueryScrollingWithInheritanceProxyTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( EmployeeParent.class );
|
||||||
|
sources.addAnnotatedClass( Employee.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScrollableWithStatelessSession() {
|
||||||
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
ScrollableResults scrollableResults = null;
|
||||||
|
final StatelessSession statelessSession = sessionFactory().openStatelessSession();
|
||||||
|
|
||||||
|
try {
|
||||||
|
statelessSession.beginTransaction();
|
||||||
|
Query<Employee> query = statelessSession.createQuery(
|
||||||
|
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( getDialect() instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
final Employee employee = (Employee) scrollableResults.get( 0 );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
|
||||||
|
if ( "ENG1".equals( employee.getDept() ) ) {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 2 ) );
|
||||||
|
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
|
||||||
|
if ( "test1".equals( otherEntity.id ) ) {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employeeParent, is( employee ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statelessSession.getTransaction().commit();
|
||||||
|
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( scrollableResults != null ) {
|
||||||
|
scrollableResults.close();
|
||||||
|
}
|
||||||
|
if ( statelessSession.getTransaction().isActive() ) {
|
||||||
|
statelessSession.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
statelessSession.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScrollableWithSession() {
|
||||||
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
ScrollableResults scrollableResults = null;
|
||||||
|
final Session session = sessionFactory().openSession();
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.beginTransaction();
|
||||||
|
Query<Employee> query = session.createQuery(
|
||||||
|
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( getDialect() instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
final Employee employee = (Employee) scrollableResults.get( 0 );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
|
||||||
|
if ( "ENG1".equals( employee.getDept() ) ) {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 2 ) );
|
||||||
|
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
|
||||||
|
if ( "test1".equals( otherEntity.id ) ) {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employeeParent, is( employee ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session.getTransaction().commit();
|
||||||
|
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( scrollableResults != null ) {
|
||||||
|
scrollableResults.close();
|
||||||
|
}
|
||||||
|
if ( session.getTransaction().isActive() ) {
|
||||||
|
session.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepareTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Employee e1 = new Employee( "ENG1" );
|
||||||
|
Employee e2 = new Employee( "ENG2" );
|
||||||
|
OtherEntity other1 = new OtherEntity( "test1" );
|
||||||
|
OtherEntity other2 = new OtherEntity( "test2" );
|
||||||
|
e1.getOtherEntities().add( other1 );
|
||||||
|
e1.getOtherEntities().add( other2 );
|
||||||
|
e1.getParentOtherEntities().add( other1 );
|
||||||
|
e1.getParentOtherEntities().add( other2 );
|
||||||
|
other1.employee = e1;
|
||||||
|
other2.employee = e1;
|
||||||
|
other1.employeeParent = e1;
|
||||||
|
other2.employeeParent = e2;
|
||||||
|
session.persist( other1 );
|
||||||
|
session.persist( other2 );
|
||||||
|
session.persist( e1 );
|
||||||
|
session.persist( e2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from EmployeeParent" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "EmployeeParent")
|
||||||
|
@Table(name = "EmployeeParent")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
public static abstract class EmployeeParent {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String dept;
|
||||||
|
|
||||||
|
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY)
|
||||||
|
protected Set<OtherEntity> parentOtherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public Set<OtherEntity> getParentOtherEntities() {
|
||||||
|
if ( parentOtherEntities == null ) {
|
||||||
|
parentOtherEntities = new LinkedHashSet();
|
||||||
|
}
|
||||||
|
return parentOtherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<OtherEntity> pParentOtherEntites) {
|
||||||
|
parentOtherEntities = pParentOtherEntites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDept() {
|
||||||
|
return dept;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDept(String dept) {
|
||||||
|
this.dept = dept;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
@Table(name = "Employee")
|
||||||
|
public static class Employee extends EmployeeParent {
|
||||||
|
|
||||||
|
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY)
|
||||||
|
protected Set<OtherEntity> otherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public Employee(String dept) {
|
||||||
|
this();
|
||||||
|
setDept( dept );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Employee() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<OtherEntity> getOtherEntities() {
|
||||||
|
if ( otherEntities == null ) {
|
||||||
|
otherEntities = new LinkedHashSet();
|
||||||
|
}
|
||||||
|
return otherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<OtherEntity> pOtherEntites) {
|
||||||
|
otherEntities = pOtherEntites;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
@JoinColumn(name = "Employee_Id")
|
||||||
|
protected Employee employee = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
@JoinColumn(name = "EmployeeParent_Id")
|
||||||
|
protected EmployeeParent employeeParent = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
hibernate-core/src/test/java/org/hibernate/test/cfg/cache/DirectReferenceCacheEntriesTest.java
vendored
Normal file
72
hibernate-core/src/test/java/org/hibernate/test/cfg/cache/DirectReferenceCacheEntriesTest.java
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* 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.cfg.cache;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Immutable;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-13665")
|
||||||
|
public class DirectReferenceCacheEntriesTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { TheEntity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
configuration.setProperty( AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
TheEntity theEntity = new TheEntity();
|
||||||
|
theEntity.setId( 1L );
|
||||||
|
session.persist( theEntity );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectANonCachablenEntity() {
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
session.createQuery( "select t from TheEntity t", TheEntity.class ).getResultList();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TheEntity")
|
||||||
|
@Table(name = "THE_ENTITY")
|
||||||
|
@Immutable
|
||||||
|
public static class TheEntity {
|
||||||
|
@Id
|
||||||
|
public Long id;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.flush;
|
||||||
|
|
||||||
|
import org.hibernate.FlushMode;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for issue https://hibernate.atlassian.net/browse/HHH-13663
|
||||||
|
*
|
||||||
|
* @author Luca Domenichini
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-13663")
|
||||||
|
public class TestHibernateFlushModeOnThreadLocalInactiveTransaction extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
configuration.setProperty( AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS, "thread" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHibernateFlushModeOnInactiveTransaction() {
|
||||||
|
try ( Session s = sessionFactory().getCurrentSession() ) {
|
||||||
|
//s.setFlushMode( FlushMode.AUTO ); // this does not throw (API is deprecated)
|
||||||
|
s.setHibernateFlushMode( FlushMode.AUTO ); // this should not throw even within an inactive transaction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,318 @@
|
||||||
|
/*
|
||||||
|
* 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.hqlfetchscroll;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.ScrollMode;
|
||||||
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.StatelessSession;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class QueryScrollingWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyStatisticsSupport( true );
|
||||||
|
sfb.applySecondLevelCacheSupport( false );
|
||||||
|
sfb.applyQueryCacheSupport( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
super.applyMetadataSources( sources );
|
||||||
|
sources.addAnnotatedClass( EmployeeParent.class );
|
||||||
|
sources.addAnnotatedClass( Employee.class );
|
||||||
|
sources.addAnnotatedClass( OtherEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScrollableWithStatelessSession() {
|
||||||
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
ScrollableResults scrollableResults = null;
|
||||||
|
final StatelessSession statelessSession = sessionFactory().openStatelessSession();
|
||||||
|
|
||||||
|
try {
|
||||||
|
statelessSession.beginTransaction();
|
||||||
|
Query<Employee> query = statelessSession.createQuery(
|
||||||
|
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( getDialect() instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
final Employee employee = (Employee) scrollableResults.get( 0 );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
|
||||||
|
if ( "ENG1".equals( employee.getDept() ) ) {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 2 ) );
|
||||||
|
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
|
||||||
|
if ( "test1".equals( otherEntity.id ) ) {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employeeParent, is( employee ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statelessSession.getTransaction().commit();
|
||||||
|
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( scrollableResults != null ) {
|
||||||
|
scrollableResults.close();
|
||||||
|
}
|
||||||
|
if ( statelessSession.getTransaction().isActive() ) {
|
||||||
|
statelessSession.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
statelessSession.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testScrollableWithSession() {
|
||||||
|
final StatisticsImplementor stats = sessionFactory().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
ScrollableResults scrollableResults = null;
|
||||||
|
final Session session = sessionFactory().openSession();
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.beginTransaction();
|
||||||
|
Query<Employee> query = session.createQuery(
|
||||||
|
"select distinct e from Employee e left join fetch e.otherEntities order by e.dept",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( getDialect() instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
final Employee employee = (Employee) scrollableResults.get( 0 );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) );
|
||||||
|
if ( "ENG1".equals( employee.getDept() ) ) {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 2 ) );
|
||||||
|
for ( OtherEntity otherEntity : employee.getOtherEntities() ) {
|
||||||
|
if ( "test1".equals( otherEntity.id ) ) {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employeeParent, is( employee ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( true ) );
|
||||||
|
assertThat( otherEntity.employee, is( employee ) );
|
||||||
|
assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) );
|
||||||
|
assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( false ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( employee.getOtherEntities().size(), is( 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session.getTransaction().commit();
|
||||||
|
assertThat( stats.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( scrollableResults != null ) {
|
||||||
|
scrollableResults.close();
|
||||||
|
}
|
||||||
|
if ( session.getTransaction().isActive() ) {
|
||||||
|
session.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepareTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
Employee e1 = new Employee( "ENG1" );
|
||||||
|
Employee e2 = new Employee( "ENG2" );
|
||||||
|
OtherEntity other1 = new OtherEntity( "test1" );
|
||||||
|
OtherEntity other2 = new OtherEntity( "test2" );
|
||||||
|
e1.getOtherEntities().add( other1 );
|
||||||
|
e1.getOtherEntities().add( other2 );
|
||||||
|
e1.getParentOtherEntities().add( other1 );
|
||||||
|
e1.getParentOtherEntities().add( other2 );
|
||||||
|
other1.employee = e1;
|
||||||
|
other2.employee = e1;
|
||||||
|
other1.employeeParent = e1;
|
||||||
|
other2.employeeParent = e2;
|
||||||
|
session.persist( other1 );
|
||||||
|
session.persist( other2 );
|
||||||
|
session.persist( e1 );
|
||||||
|
session.persist( e2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUpTestData() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from EmployeeParent" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "EmployeeParent")
|
||||||
|
@Table(name = "EmployeeParent")
|
||||||
|
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||||
|
public static abstract class EmployeeParent {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String dept;
|
||||||
|
|
||||||
|
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY)
|
||||||
|
protected Set<OtherEntity> parentOtherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public Set<OtherEntity> getParentOtherEntities() {
|
||||||
|
if ( parentOtherEntities == null ) {
|
||||||
|
parentOtherEntities = new LinkedHashSet();
|
||||||
|
}
|
||||||
|
return parentOtherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<OtherEntity> pParentOtherEntites) {
|
||||||
|
parentOtherEntities = pParentOtherEntites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDept() {
|
||||||
|
return dept;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDept(String dept) {
|
||||||
|
this.dept = dept;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
@Table(name = "Employee")
|
||||||
|
public static class Employee extends EmployeeParent {
|
||||||
|
|
||||||
|
@OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY)
|
||||||
|
protected Set<OtherEntity> otherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public Employee(String dept) {
|
||||||
|
this();
|
||||||
|
setDept( dept );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Employee() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<OtherEntity> getOtherEntities() {
|
||||||
|
if ( otherEntities == null ) {
|
||||||
|
otherEntities = new LinkedHashSet();
|
||||||
|
}
|
||||||
|
return otherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<OtherEntity> pOtherEntites) {
|
||||||
|
otherEntities = pOtherEntites;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntity")
|
||||||
|
@Table(name = "OtherEntity")
|
||||||
|
public static class OtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "Employee_Id")
|
||||||
|
protected Employee employee = null;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "EmployeeParent_Id")
|
||||||
|
protected EmployeeParent employeeParent = null;
|
||||||
|
|
||||||
|
protected OtherEntity() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntity(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* 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>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.manytomany.mapkey;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.JoinTable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.MapKey;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
|
||||||
|
import org.hibernate.testing.DialectChecks;
|
||||||
|
import org.hibernate.testing.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.core.Is.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-4235")
|
||||||
|
@RequiresDialectFeature(DialectChecks.SupportSchemaCreation.class)
|
||||||
|
public class ManyToManyWithMaykeyAndSchemaDefinitionTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
configuration.setProperty( AvailableSettings.HBM2DDL_CREATE_SCHEMAS, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { EntityA.class, EntityB.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
EntityA entityA = new EntityA();
|
||||||
|
entityA.setId( 1L );
|
||||||
|
|
||||||
|
EntityB entityB = new EntityB();
|
||||||
|
entityB.setId( 1L );
|
||||||
|
entityA.setEntityBs( "B", entityB );
|
||||||
|
session.persist( entityB );
|
||||||
|
session.persist( entityA );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRetrievingTheMapGeneratesACorrectlyQuery() {
|
||||||
|
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
EntityA entityA = session.get( EntityA.class, 1L );
|
||||||
|
Collection<EntityB> values = entityA.getEntityBMap().values();
|
||||||
|
assertThat( values.size(), is( 1 ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity(name = "EntityA")
|
||||||
|
@Table(name = "entitya", schema = "myschema")
|
||||||
|
public static class EntityA {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@MapKey(name = "id")
|
||||||
|
@JoinTable(name = "entitya_entityb", schema = "myschema", joinColumns = @JoinColumn(name = "entitya_pk"), inverseJoinColumns = @JoinColumn(name = "entityb_pk"))
|
||||||
|
private Map<String, EntityB> entityBMap = new HashMap<>();
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntityBs(String key, EntityB entityB) {
|
||||||
|
this.entityBMap.put( key, entityB );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, EntityB> getEntityBMap() {
|
||||||
|
return entityBMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "EntityB")
|
||||||
|
@Table(name = "entityb", schema = "myschema")
|
||||||
|
public static class EntityB {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue