From 859b61a7c4e315bfabda279ab3bbbb282a5df963 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 12 Aug 2011 11:47:34 -0500 Subject: [PATCH] HHH-6503 - Develop Set-style plural attribute support for new metamodel --- .../java/org/hibernate/engine/FetchStyle.java | 52 ++++ .../org/hibernate/engine/FetchTiming.java | 45 ++++ .../internal/SessionFactoryImpl.java | 35 +-- .../AbstractPluralAttributeBinding.java | 225 ++++++++++++------ .../binding/AssociationAttributeBinding.java | 18 +- .../metamodel/binding/CollectionLaziness.java | 33 +++ .../binding/ManyToOneAttributeBinding.java | 42 +++- .../binding/PluralAttributeBinding.java | 38 ++- .../domain/AbstractAttributeContainer.java | 11 + .../metamodel/domain/AttributeContainer.java | 10 + .../hibernate/metamodel/domain/Component.java | 7 + .../metamodel/domain/PluralAttribute.java | 1 + .../attribute/ToOneAttributeSourceImpl.java | 14 ++ .../binder/AssociationAttributeSource.java | 6 + .../source/binder/AttributeSource.java | 21 ++ .../metamodel/source/binder/Binder.java | 72 +++++- .../source/binder/PluralAttributeNature.java | 25 +- .../source/binder/PluralAttributeSource.java | 22 ++ .../binder/SingularAttributeSource.java | 25 -- .../AbstractPluralAttributeSourceImpl.java | 158 +++++++++++- .../hbm/ManyToOneAttributeSourceImpl.java | 79 ++++++ 21 files changed, 792 insertions(+), 147 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/FetchStyle.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/binding/CollectionLaziness.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/FetchStyle.java b/hibernate-core/src/main/java/org/hibernate/engine/FetchStyle.java new file mode 100644 index 0000000000..8947cdc5d0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/FetchStyle.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine; + +/** + * Enumeration of values describing HOW fetching should occur. + * + * @author Steve Ebersole + * @see FetchTiming + */ +public enum FetchStyle { + /** + * Performs a separate SQL select to load the indicated data. This can either be eager (the second select is + * issued immediately) or lazy (the second select is delayed until the data is needed). + */ + SELECT, + /** + * Inherently an eager style of fetching. The data to be fetched is obtained as part of an SQL join. + */ + JOIN, + /** + * Initializes a number of indicated data items (entities or collections) in a series of grouped sql selects + * using an in-style sql restriction to define the batch size. Again, can be either eager or lazy. + */ + BATCH, + /** + * Performs fetching of associated data (currently limited to only collections) based on the sql restriction + * used to load the owner. Again, can be either eager or lazy. + */ + SUBSELECT +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java b/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java new file mode 100644 index 0000000000..0b1144d5cb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/FetchTiming.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.engine; + +/** + * Enumeration of values describing WHEN fetching should occur. + * + * @author Steve Ebersole + * @see FetchStyle + */ +public enum FetchTiming { + /** + * Perform fetching immediately. Also called eager fetching + */ + IMMEDIATE, + /** + * Performing fetching later, when needed. Also called lazy fetching. + */ + DELAYED, + /** + * Take extra care to ensure laziness. Only available in regards to collections + */ + EXTRA_LAZY +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index b73ac408f9..334ce84151 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -640,12 +640,9 @@ public void sessionFactoryClosed(SessionFactory factory) { if ( accessStrategy == null ) { final AccessType accessType = model.getHierarchyDetails().getCaching().getAccessType(); LOG.trace("Building cache for entity data [" + model.getEntity().getName() + "]"); - EntityRegion entityRegion = - settings.getRegionFactory().buildEntityRegion( - cacheRegionName, - properties, - CacheDataDescriptionImpl.decode( model ) - ); + EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( + cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) + ); accessStrategy = entityRegion.buildAccessStrategy( accessType ); entityAccessStrategies.put( cacheRegionName, accessStrategy ); allCacheRegions.put( cacheRegionName, entityRegion ); @@ -670,28 +667,22 @@ public void sessionFactoryClosed(SessionFactory factory) { "AbstractPluralAttributeBinding has a Singular attribute defined: " + model.getAttribute().getName() ); } - // TODO: Add AbstractPluralAttributeBinding.getCaching() - final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName(); - final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() ); + final String cacheRegionName = cacheRegionPrefix + model.getCaching().getRegion(); + final AccessType accessType = model.getCaching().getAccessType(); CollectionRegionAccessStrategy accessStrategy = null; if ( accessType != null && settings.isSecondLevelCacheEnabled() ) { - // TODO: is model.locateAttribute().getName() the collection's role??? For now, assuming it is - LOG.trace("Building cache for collection data [" + model.getAttribute().getName() + "]"); - CollectionRegion collectionRegion = - settings.getRegionFactory() - .buildCollectionRegion( - cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) - ); + LOG.trace("Building cache for collection data [" + model.getAttribute().getRole() + "]"); + CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( + cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) + ); accessStrategy = collectionRegion.buildAccessStrategy( accessType ); entityAccessStrategies.put( cacheRegionName, accessStrategy ); allCacheRegions.put( cacheRegionName, collectionRegion ); } - CollectionPersister persister = - serviceRegistry - .getService( PersisterFactory.class ) - .createCollectionPersister( metadata, model, accessStrategy, this ); - // TODO: is model.locateAttribute().getName() the collection's role??? For now, assuming it is - collectionPersisters.put( model.getAttribute().getName(), persister.getCollectionMetadata() ); + CollectionPersister persister = serviceRegistry + .getService( PersisterFactory.class ) + .createCollectionPersister( metadata, model, accessStrategy, this ); + collectionPersisters.put( model.getAttribute().getRole(), persister.getCollectionMetadata() ); Type indexType = persister.getIndexType(); if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) { String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractPluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractPluralAttributeBinding.java index 598b30b221..d047a61bb6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractPluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractPluralAttributeBinding.java @@ -31,11 +31,13 @@ import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; -import org.hibernate.metamodel.domain.Attribute; import org.hibernate.metamodel.domain.PluralAttribute; import org.hibernate.metamodel.relational.Table; import org.hibernate.metamodel.relational.TableSpecification; +import org.hibernate.persister.collection.CollectionPersister; /** * TODO : javadoc @@ -48,36 +50,37 @@ public abstract class AbstractPluralAttributeBinding extends AbstractAttributeBi private Table collectionTable; - private CascadeStyle cascadeStyle; - private FetchMode fetchMode; + private FetchTiming fetchTiming; + private FetchStyle fetchStyle; + private int batchSize = -1; + + private CascadeStyle cascadeStyle; + private boolean orphanDelete; + + private Caching caching; - private boolean extraLazy; private boolean inverse; private boolean mutable = true; - private boolean subselectLoadable; - private String cacheConcurrencyStrategy; - private String cacheRegionName; - private String orderBy; + + private Class collectionPersisterClass; + private String where; - private String referencedPropertyName; + private String orderBy; private boolean sorted; private Comparator comparator; private String comparatorClassName; - private boolean orphanDelete; - private int batchSize = -1; - private boolean embedded = true; - private boolean optimisticLocked = true; - private Class collectionPersisterClass; + + private String customLoaderName; + private CustomSQL customSqlInsert; + private CustomSQL customSqlUpdate; + private CustomSQL customSqlDelete; + private CustomSQL customSqlDeleteAll; + + private String referencedPropertyName; + private final java.util.Map filters = new HashMap(); private final java.util.Set synchronizedTables = new HashSet(); - private CustomSQL customSQLInsert; - private CustomSQL customSQLUpdate; - private CustomSQL customSQLDelete; - private CustomSQL customSQLDeleteAll; - - private String loaderName; - protected AbstractPluralAttributeBinding( AttributeBindingContainer container, PluralAttribute attribute, @@ -156,6 +159,7 @@ public boolean isAssociation() { || collectionElement.getCollectionElementNature() == CollectionElementNature.ONE_TO_MANY; } + @Override public TableSpecification getCollectionTable() { return collectionTable; } @@ -164,10 +168,12 @@ public void setCollectionTable(Table collectionTable) { this.collectionTable = collectionTable; } + @Override public CollectionKey getCollectionKey() { return collectionKey; } + @Override public AbstractCollectionElement getCollectionElement() { return collectionElement; } @@ -184,7 +190,12 @@ public void setCascadeStyles(Iterable cascadeStyles) { if ( style != CascadeStyle.NONE ) { cascadeStyleList.add( style ); } + if ( style == CascadeStyle.DELETE_ORPHAN || + style == CascadeStyle.ALL_DELETE_ORPHAN ) { + orphanDelete = true; + } } + if ( cascadeStyleList.isEmpty() ) { cascadeStyle = CascadeStyle.NONE; } @@ -199,39 +210,102 @@ else if ( cascadeStyleList.size() == 1 ) { } @Override - public FetchMode getFetchMode() { - return fetchMode; + public boolean isOrphanDelete() { + return orphanDelete; } @Override - public void setFetchMode(FetchMode fetchMode) { - this.fetchMode = fetchMode; + public FetchMode getFetchMode() { + if ( getFetchStyle() == FetchStyle.JOIN ) { + return FetchMode.JOIN; + } + else { + return FetchMode.SELECT; + } } - public boolean isExtraLazy() { - return extraLazy; + @Override + public FetchTiming getFetchTiming() { + return fetchTiming; } - public boolean isInverse() { - return inverse; + @Override + public void setFetchTiming(FetchTiming fetchTiming) { + this.fetchTiming = fetchTiming; } - public boolean isMutable() { - return mutable; + @Override + public FetchStyle getFetchStyle() { + return fetchStyle; } - public boolean isSubselectLoadable() { - return subselectLoadable; + @Override + public void setFetchStyle(FetchStyle fetchStyle) { + this.fetchStyle = fetchStyle; } - public String getCacheConcurrencyStrategy() { - return cacheConcurrencyStrategy; + @Override + public String getCustomLoaderName() { + return customLoaderName; } - public String getCacheRegionName() { - return cacheRegionName; + public void setCustomLoaderName(String customLoaderName) { + this.customLoaderName = customLoaderName; } + @Override + public CustomSQL getCustomSqlInsert() { + return customSqlInsert; + } + + public void setCustomSqlInsert(CustomSQL customSqlInsert) { + this.customSqlInsert = customSqlInsert; + } + + @Override + public CustomSQL getCustomSqlUpdate() { + return customSqlUpdate; + } + + public void setCustomSqlUpdate(CustomSQL customSqlUpdate) { + this.customSqlUpdate = customSqlUpdate; + } + + @Override + public CustomSQL getCustomSqlDelete() { + return customSqlDelete; + } + + public void setCustomSqlDelete(CustomSQL customSqlDelete) { + this.customSqlDelete = customSqlDelete; + } + + @Override + public CustomSQL getCustomSqlDeleteAll() { + return customSqlDeleteAll; + } + + public void setCustomSqlDeleteAll(CustomSQL customSqlDeleteAll) { + this.customSqlDeleteAll = customSqlDeleteAll; + } + + public Class getCollectionPersisterClass() { + return collectionPersisterClass; + } + + public void setCollectionPersisterClass(Class collectionPersisterClass) { + this.collectionPersisterClass = collectionPersisterClass; + } + + public Caching getCaching() { + return caching; + } + + public void setCaching(Caching caching) { + this.caching = caching; + } + + @Override public String getOrderBy() { return orderBy; } @@ -240,6 +314,7 @@ public void setOrderBy(String orderBy) { this.orderBy = orderBy; } + @Override public String getWhere() { return where; } @@ -248,14 +323,53 @@ public void setWhere(String where) { this.where = where; } + @Override + public boolean isInverse() { + return inverse; + } + + public void setInverse(boolean inverse) { + this.inverse = inverse; + } + + @Override + public boolean isMutable() { + return mutable; + } + + public void setMutable(boolean mutable) { + this.mutable = mutable; + } + + @Override + public int getBatchSize() { + return batchSize; + } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + + + + + + + + + + public String getReferencedPropertyName() { return referencedPropertyName; } + @Override public boolean isSorted() { return sorted; } + @Override public Comparator getComparator() { return comparator; } @@ -268,47 +382,12 @@ public String getComparatorClassName() { return comparatorClassName; } - public boolean isOrphanDelete() { - return orphanDelete; - } - - public int getBatchSize() { - return batchSize; - } - - public boolean isEmbedded() { - return embedded; - } - - public Class getCollectionPersisterClass() { - return collectionPersisterClass; - } - public void addFilter(String name, String condition) { filters.put( name, condition ); } + @Override public java.util.Map getFilterMap() { return filters; } - - public CustomSQL getCustomSQLInsert() { - return customSQLInsert; - } - - public CustomSQL getCustomSQLUpdate() { - return customSQLUpdate; - } - - public CustomSQL getCustomSQLDelete() { - return customSQLDelete; - } - - public CustomSQL getCustomSQLDeleteAll() { - return customSQLDeleteAll; - } - - public String getLoaderName() { - return loaderName; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AssociationAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AssociationAttributeBinding.java index 6f68ad6675..7480a42dc1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AssociationAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AssociationAttributeBinding.java @@ -24,6 +24,8 @@ package org.hibernate.metamodel.binding; import org.hibernate.FetchMode; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; /** @@ -46,7 +48,19 @@ public interface AssociationAttributeBinding extends AttributeBinding { */ public void setCascadeStyles(Iterable cascadeStyles); - public FetchMode getFetchMode(); + public FetchTiming getFetchTiming(); + public void setFetchTiming(FetchTiming fetchTiming); - public void setFetchMode(FetchMode fetchMode); + public FetchStyle getFetchStyle(); + public void setFetchStyle(FetchStyle fetchStyle); + + + /** + * Temporary. Needed for integration with legacy {@link org.hibernate.mapping} configuration of persisters. + * + * @deprecated + */ + @Deprecated + @SuppressWarnings( {"JavaDoc"}) + public FetchMode getFetchMode(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/CollectionLaziness.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/CollectionLaziness.java new file mode 100644 index 0000000000..72240474c9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/CollectionLaziness.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.metamodel.binding; + +/** + * @author Steve Ebersole + */ +public enum CollectionLaziness { + LAZY, + NOT, + EXTRA +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java index 4b8a36fd57..93876ba1bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java @@ -28,6 +28,8 @@ import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.metamodel.domain.SingularAttribute; @@ -46,7 +48,8 @@ public class ManyToOneAttributeBinding extends BasicAttributeBinding implements private String foreignKeyName; private CascadeStyle cascadeStyle; - private FetchMode fetchMode; + private FetchTiming fetchTiming; + private FetchStyle fetchStyle; ManyToOneAttributeBinding(AttributeBindingContainer container, SingularAttribute attribute) { super( container, attribute, false, false ); @@ -109,13 +112,42 @@ else if ( cascadeStyleList.size() == 1 ) { } @Override - public FetchMode getFetchMode() { - return fetchMode; + public FetchTiming getFetchTiming() { + return fetchTiming; } @Override - public void setFetchMode(FetchMode fetchMode) { - this.fetchMode = fetchMode; + public void setFetchTiming(FetchTiming fetchTiming) { + this.fetchTiming = fetchTiming; + } + + @Override + public FetchStyle getFetchStyle() { + return fetchStyle; + } + + @Override + public void setFetchStyle(FetchStyle fetchStyle) { + if ( fetchStyle == FetchStyle.SUBSELECT ) { + throw new AssertionFailure( "Subselect fetching not yet supported for singular associations" ); + } + this.fetchStyle = fetchStyle; + } + + @Override + public FetchMode getFetchMode() { + if ( fetchStyle == FetchStyle.JOIN ) { + return FetchMode.JOIN; + } + else if ( fetchStyle == FetchStyle.SELECT ) { + return FetchMode.SELECT; + } + else if ( fetchStyle == FetchStyle.BATCH ) { + // we need the subsequent select... + return FetchMode.SELECT; + } + + throw new AssertionFailure( "Unexpected fetch style : " + fetchStyle.name() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java index d1b7e0357a..b504f79b9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java @@ -23,6 +23,11 @@ */ package org.hibernate.metamodel.binding; +import java.util.Comparator; + +import org.hibernate.engine.FetchTiming; +import org.hibernate.metamodel.domain.Attribute; +import org.hibernate.metamodel.domain.PluralAttribute; import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.persister.collection.CollectionPersister; @@ -32,6 +37,9 @@ public interface PluralAttributeBinding extends AssociationAttributeBinding { // todo : really it is the element (and/or index) that can be associative not the collection itself... + @Override + public PluralAttribute getAttribute(); + public CollectionKey getCollectionKey(); public AbstractCollectionElement getCollectionElement(); @@ -40,9 +48,33 @@ public interface PluralAttributeBinding extends AssociationAttributeBinding { public boolean isMutable(); - public String getCacheRegionName(); + public Caching getCaching(); - public String getCacheConcurrencyStrategy(); + public Class getCollectionPersisterClass(); - public Class getCollectionPersisterClass(); + public String getCustomLoaderName(); + + public CustomSQL getCustomSqlInsert(); + + public CustomSQL getCustomSqlUpdate(); + + public CustomSQL getCustomSqlDelete(); + + public CustomSQL getCustomSqlDeleteAll(); + + public boolean isOrphanDelete(); + + String getWhere(); + + boolean isSorted(); + + Comparator getComparator(); + + int getBatchSize(); + + java.util.Map getFilterMap(); + + boolean isInverse(); + + String getOrderBy(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AbstractAttributeContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AbstractAttributeContainer.java index 51cda724c1..941cbb580c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AbstractAttributeContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AbstractAttributeContainer.java @@ -29,6 +29,7 @@ import java.util.Set; import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.Value; /** @@ -83,6 +84,11 @@ public Set attributes() { return Collections.unmodifiableSet( attributeSet ); } + @Override + public String getRoleBaseName() { + return getClassName(); + } + @Override public Attribute locateAttribute(String name) { return attributeMap.get( name ); @@ -266,6 +272,11 @@ public String getName() { return name; } + @Override + public String getRole() { + return StringHelper.qualify( attributeContainer.getRoleBaseName(), name ); + } + @Override public Type getElementType() { return elementType; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AttributeContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AttributeContainer.java index 4ead828994..6024c758e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AttributeContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/AttributeContainer.java @@ -32,6 +32,16 @@ * @author Steve Ebersole */ public interface AttributeContainer extends Type { + /** + * Obtain the name of this container in terms of creating attribute role names. + *

+ * NOTE : A role uniquely names each attribute. The role name is the name of the attribute prefixed by the "path" + * to its container. + * + * @return The container base name for role construction. + */ + public String getRoleBaseName(); + /** * Retrieve an attribute by name. * diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/Component.java b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/Component.java index b8b90a802c..c12296825e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/Component.java @@ -46,4 +46,11 @@ public boolean isAssociation() { public boolean isComponent() { return true; } + + @Override + public String getRoleBaseName() { + // todo : this is not really completely accurate atm + // the role base here should really be the role of the component attribute. + return getClassName(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/PluralAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/PluralAttribute.java index 1d5ca53ad3..4914f05da1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/domain/PluralAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/domain/PluralAttribute.java @@ -29,6 +29,7 @@ * @author Steve Ebersole */ public interface PluralAttribute extends Attribute { + public String getRole(); public PluralAttributeNature getNature(); public Type getElementType(); public void setElementType(Type elementType); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/attribute/ToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/attribute/ToOneAttributeSourceImpl.java index 0b5b0294b7..3eae19acdc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/attribute/ToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/attribute/ToOneAttributeSourceImpl.java @@ -26,6 +26,8 @@ import java.util.Set; import org.hibernate.FetchMode; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.metamodel.source.annotations.EnumConversionHelper; import org.hibernate.metamodel.source.binder.SingularAttributeNature; @@ -68,6 +70,18 @@ public Iterable getCascadeStyles() { public FetchMode getFetchMode() { return associationAttribute.getFetchMode(); } + + @Override + public FetchTiming getFetchTiming() { + // todo : implement + return FetchTiming.IMMEDIATE; + } + + @Override + public FetchStyle getFetchStyle() { + // todo : implement + return FetchStyle.JOIN; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AssociationAttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AssociationAttributeSource.java index 90a8c80b61..57743a69e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AssociationAttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AssociationAttributeSource.java @@ -24,6 +24,8 @@ package org.hibernate.metamodel.source.binder; import org.hibernate.FetchMode; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; /** @@ -45,4 +47,8 @@ public interface AssociationAttributeSource extends AttributeSource { * @return The fetch mode. */ public FetchMode getFetchMode(); + + public FetchTiming getFetchTiming(); + + public FetchStyle getFetchStyle(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AttributeSource.java index 41344107bf..2999634f1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/AttributeSource.java @@ -43,8 +43,29 @@ public interface AttributeSource { */ public boolean isSingular(); + /** + * Obtain information about the Hibernate type ({@link org.hibernate.type.Type}) for this attribute. + * + * @return The Hibernate type information + */ + public ExplicitHibernateTypeSource getTypeInformation(); + + /** + * Obtain the name of the property accessor style used to access this attribute. + * + * @return The property accessor style for this attribute. + * + * @see org.hibernate.property.PropertyAccessor + */ public String getPropertyAccessorName(); + /** + * If the containing entity is using {@link org.hibernate.engine.OptimisticLockStyle#ALL} or + * {@link org.hibernate.engine.OptimisticLockStyle#DIRTY} style optimistic locking, should this attribute + * be used? + * + * @return {@code true} indicates it should be included; {@code false}, it should not. + */ public boolean isIncludedInOptimisticLocking(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/Binder.java index b886c4b032..1901e11f90 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/Binder.java @@ -42,6 +42,7 @@ import org.hibernate.metamodel.binding.BasicAttributeBinding; import org.hibernate.metamodel.binding.BasicCollectionElement; import org.hibernate.metamodel.binding.CollectionElementNature; +import org.hibernate.metamodel.binding.CollectionLaziness; import org.hibernate.metamodel.binding.ComponentAttributeBinding; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityDiscriminator; @@ -67,9 +68,11 @@ import org.hibernate.metamodel.relational.Tuple; import org.hibernate.metamodel.relational.UniqueKey; import org.hibernate.metamodel.source.LocalBindingContext; +import org.hibernate.metamodel.source.MappingException; import org.hibernate.metamodel.source.MetaAttributeContext; import org.hibernate.metamodel.source.MetadataImplementor; import org.hibernate.metamodel.source.hbm.Helper; +import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.tuple.entity.EntityTuplizer; @@ -477,7 +480,7 @@ else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SE } else { // todo : implement other collection types - throw new NotYetImplementedException( "Collections other than bag not yet implemented :(" ); + throw new NotYetImplementedException( "Collections other than bag and set not yet implemented :(" ); } doBasicPluralAttributeBinding( attributeSource, pluralAttributeBinding ); @@ -492,20 +495,66 @@ else if ( attributeSource.getPluralAttributeNature() == PluralAttributeNature.SE metadata.addCollection( pluralAttributeBinding ); } - private void doBasicPluralAttributeBinding( - PluralAttributeSource attributeSource, - AbstractPluralAttributeBinding pluralAttributeBinding) { - pluralAttributeBinding.setFetchMode( attributeSource.getFetchMode() ); - pluralAttributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() ); + private void doBasicPluralAttributeBinding(PluralAttributeSource source, AbstractPluralAttributeBinding binding) { + binding.setFetchTiming( source.getFetchTiming() ); + binding.setFetchStyle( source.getFetchStyle() ); + binding.setCascadeStyles( source.getCascadeStyles() ); - pluralAttributeBinding.setMetaAttributeContext( + binding.setCaching( source.getCaching() ); + + binding.getHibernateTypeDescriptor().setJavaTypeName( + source.getPluralAttributeNature().reportedJavaType().getName() + ); + binding.getHibernateTypeDescriptor().setExplicitTypeName( source.getTypeInformation().getName() ); + binding.getHibernateTypeDescriptor().getTypeParameters().putAll( source.getTypeInformation().getParameters() ); + + if ( StringHelper.isNotEmpty( source.getCustomPersisterClassName() ) ) { + binding.setCollectionPersisterClass( + currentBindingContext.locateClassByName( source.getCustomPersisterClassName() ) + ); + } + + if ( source.getCustomPersisterClassName() != null ) { + binding.setCollectionPersisterClass( + metadata.locateClassByName( source.getCustomPersisterClassName() ) + ); + } + + binding.setCustomLoaderName( source.getCustomLoaderName() ); + binding.setCustomSqlInsert( source.getCustomSqlInsert() ); + binding.setCustomSqlUpdate( source.getCustomSqlUpdate() ); + binding.setCustomSqlDelete( source.getCustomSqlDelete() ); + binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() ); + + binding.setMetaAttributeContext( buildMetaAttributeContext( - attributeSource.metaAttributes(), - pluralAttributeBinding.getContainer().getMetaAttributeContext() + source.metaAttributes(), + binding.getContainer().getMetaAttributeContext() ) ); - doBasicAttributeBinding( attributeSource, pluralAttributeBinding ); + doBasicAttributeBinding( source, binding ); + } + + private CollectionLaziness interpretLaziness(String laziness) { + if ( laziness == null ) { + laziness = Boolean.toString( metadata.getMappingDefaults().areAssociationsLazy() ); + } + + if ( "extra".equals( laziness ) ) { + return CollectionLaziness.EXTRA; + } + else if ( "false".equals( laziness ) ) { + return CollectionLaziness.NOT; + } + else if ( "true".equals( laziness ) ) { + return CollectionLaziness.LAZY; + } + + throw new MappingException( + String.format( "Unexpected collection laziness value %s", laziness ), + currentBindingContext.getOrigin() + ); } private void bindCollectionTable( @@ -856,7 +905,8 @@ private void resolveToOneInformation(ToOneAttributeSource attributeSource, ManyT attributeBinding.setReferencedAttributeName( attributeSource.getReferencedEntityAttributeName() ); attributeBinding.setCascadeStyles( attributeSource.getCascadeStyles() ); - attributeBinding.setFetchMode( attributeSource.getFetchMode() ); + attributeBinding.setFetchTiming( attributeSource.getFetchTiming() ); + attributeBinding.setFetchStyle( attributeSource.getFetchStyle() ); } private MetaAttributeContext buildMetaAttributeContext(EntitySource entitySource) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeNature.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeNature.java index 1bd35fa9e8..9c766e0735 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeNature.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeNature.java @@ -23,15 +23,30 @@ */ package org.hibernate.metamodel.source.binder; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * Describes the nature of the collection itself as declared by the metadata. * * @author Steve Ebersole */ public enum PluralAttributeNature { - BAG, - ID_BAG, - SET, - LIST, - MAP + BAG( Collection.class ), + ID_BAG( Collection.class ), + SET( Set.class ), + LIST( List.class ), + MAP( Map.class ); + + private final Class reportedJavaType; + + PluralAttributeNature(Class reportedJavaType) { + this.reportedJavaType = reportedJavaType; + } + + public Class reportedJavaType() { + return reportedJavaType; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeSource.java index 7a01606811..2f19b86b61 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/PluralAttributeSource.java @@ -23,6 +23,9 @@ */ package org.hibernate.metamodel.source.binder; +import org.hibernate.metamodel.binding.Caching; +import org.hibernate.metamodel.binding.CustomSQL; + /** * @author Steve Ebersole */ @@ -40,7 +43,26 @@ public interface PluralAttributeSource extends AssociationAttributeSource { public String getCollectionTableComment(); public String getCollectionTableCheck(); + public Caching getCaching(); + + /** + * Obtain the name of a custom persister class to be used. + * + * @return The custom persister class name + */ + public String getCustomPersisterClassName(); + public String getWhere(); public boolean isInverse(); + + public String getCustomLoaderName(); + + public CustomSQL getCustomSqlInsert(); + + public CustomSQL getCustomSqlUpdate(); + + public CustomSQL getCustomSqlDelete(); + + public CustomSQL getCustomSqlDeleteAll(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/SingularAttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/SingularAttributeSource.java index b371f9a2cf..33978afb0f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/SingularAttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/binder/SingularAttributeSource.java @@ -46,22 +46,6 @@ public interface SingularAttributeSource extends AttributeSource, RelationalValu */ public SingularAttributeNature getNature(); - /** - * Obtain information about the Hibernate type ({@link org.hibernate.type.Type}) for this attribute. - * - * @return The Hibernate type information - */ - public ExplicitHibernateTypeSource getTypeInformation(); - - /** - * Obtain the name of the property accessor style used to access this attribute. - * - * @return The property accessor style for this attribute. - * - * @see org.hibernate.property.PropertyAccessor - */ - public String getPropertyAccessorName(); - /** * Determine whether this attribute is insertable. * @@ -91,13 +75,4 @@ public interface SingularAttributeSource extends AttributeSource, RelationalValu * @return {@code true} to indicate the attribute should be lazily loaded. */ public boolean isLazy(); - - /** - * If the containing entity is using {@link org.hibernate.engine.OptimisticLockStyle#ALL} or - * {@link org.hibernate.engine.OptimisticLockStyle#DIRTY} style optimistic locking, should this attribute - * be used? - * - * @return {@code true} indicates it should be included; {@code false}, it should not. - */ - public boolean isIncludedInOptimisticLocking(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractPluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractPluralAttributeSourceImpl.java index baf606c12f..61c88ad404 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractPluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractPluralAttributeSourceImpl.java @@ -23,17 +23,28 @@ */ package org.hibernate.metamodel.source.hbm; +import java.util.Collections; +import java.util.Map; + import org.hibernate.FetchMode; +import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.binding.Caching; +import org.hibernate.metamodel.binding.CustomSQL; import org.hibernate.metamodel.source.LocalBindingContext; import org.hibernate.metamodel.source.MappingException; import org.hibernate.metamodel.source.binder.AttributeSourceContainer; +import org.hibernate.metamodel.source.binder.ExplicitHibernateTypeSource; import org.hibernate.metamodel.source.binder.MetaAttributeSource; import org.hibernate.metamodel.source.binder.PluralAttributeElementSource; import org.hibernate.metamodel.source.binder.PluralAttributeKeySource; import org.hibernate.metamodel.source.binder.PluralAttributeSource; import org.hibernate.metamodel.source.hbm.jaxb.mapping.PluralAttributeElement; +import org.hibernate.metamodel.source.hbm.jaxb.mapping.XMLCacheElement; /** * @author Steve Ebersole @@ -42,17 +53,31 @@ public abstract class AbstractPluralAttributeSourceImpl implements PluralAttribu private final PluralAttributeElement pluralAttributeElement; private final AttributeSourceContainer container; + private final ExplicitHibernateTypeSource typeInformation; + private final PluralAttributeKeySource keySource; private final PluralAttributeElementSource elementSource; protected AbstractPluralAttributeSourceImpl( - PluralAttributeElement pluralAttributeElement, + final PluralAttributeElement pluralAttributeElement, AttributeSourceContainer container) { this.pluralAttributeElement = pluralAttributeElement; this.container = container; this.keySource = new PluralAttributeKeySourceImpl( pluralAttributeElement.getKey(), container ); this.elementSource = interpretElementType(); + + this.typeInformation = new ExplicitHibernateTypeSource() { + @Override + public String getName() { + return pluralAttributeElement.getCollectionType(); + } + + @Override + public Map getParameters() { + return Collections.emptyMap(); + } + }; } private PluralAttributeElementSource interpretElementType() { @@ -135,6 +160,20 @@ public String getCollectionTableCheck() { return pluralAttributeElement.getCheck(); } + @Override + public Caching getCaching() { + final XMLCacheElement cache = pluralAttributeElement.getCache(); + if ( cache == null ) { + return null; + } + final String region = cache.getRegion() != null + ? cache.getRegion() + : StringHelper.qualify( container().getPath(), getName() ); + final AccessType accessType = Enum.valueOf( AccessType.class, cache.getUsage() ); + final boolean cacheLazyProps = !"non-lazy".equals( cache.getInclude() ); + return new Caching( region, accessType, cacheLazyProps ); + } + @Override public String getWhere() { return pluralAttributeElement.getWhere(); @@ -150,6 +189,11 @@ public boolean isSingular() { return false; } + @Override + public ExplicitHibernateTypeSource getTypeInformation() { + return typeInformation; + } + @Override public String getPropertyAccessorName() { return pluralAttributeElement.getAccess(); @@ -165,6 +209,38 @@ public boolean isInverse() { return pluralAttributeElement.isInverse(); } + @Override + public String getCustomPersisterClassName() { + return pluralAttributeElement.getPersister(); + } + + @Override + public String getCustomLoaderName() { + return pluralAttributeElement.getLoader() == null + ? null + : pluralAttributeElement.getLoader().getQueryRef(); + } + + @Override + public CustomSQL getCustomSqlInsert() { + return Helper.buildCustomSql( pluralAttributeElement.getSqlInsert() ); + } + + @Override + public CustomSQL getCustomSqlUpdate() { + return Helper.buildCustomSql( pluralAttributeElement.getSqlUpdate() ); + } + + @Override + public CustomSQL getCustomSqlDelete() { + return Helper.buildCustomSql( pluralAttributeElement.getSqlDelete() ); + } + + @Override + public CustomSQL getCustomSqlDeleteAll() { + return Helper.buildCustomSql( pluralAttributeElement.getSqlDeleteAll() ); + } + @Override public Iterable metaAttributes() { return Helper.buildMetaAttributeSources( pluralAttributeElement.getMeta() ); @@ -175,6 +251,86 @@ public Iterable getCascadeStyles() { return Helper.interpretCascadeStyles( pluralAttributeElement.getCascade(), bindingContext() ); } + @Override + public FetchTiming getFetchTiming() { + final String fetchSelection = pluralAttributeElement.getFetch() != null ? + pluralAttributeElement.getFetch().value() : + null; + final String lazySelection = pluralAttributeElement.getLazy() != null + ? pluralAttributeElement.getLazy().value() + : null; + final String outerJoinSelection = pluralAttributeElement.getOuterJoin() != null + ? pluralAttributeElement.getOuterJoin().value() + : null; + + if ( lazySelection == null ) { + if ( "join".equals( fetchSelection ) || "true".equals( outerJoinSelection ) ) { + return FetchTiming.IMMEDIATE; + } + else if ( "false".equals( outerJoinSelection ) ) { + return FetchTiming.DELAYED; + } + else { + return bindingContext().getMappingDefaults().areAssociationsLazy() + ? FetchTiming.DELAYED + : FetchTiming.IMMEDIATE; + } + } + else if ( "extra".equals( lazySelection ) ) { + return FetchTiming.EXTRA_LAZY; + } + else if ( "true".equals( lazySelection ) ) { + return FetchTiming.DELAYED; + } + else if ( "false".equals( lazySelection ) ) { + return FetchTiming.IMMEDIATE; + } + + throw new MappingException( + String.format( + "Unexpected lazy selection [%s] on '%s'", + lazySelection, + pluralAttributeElement.getName() + ), + bindingContext().getOrigin() + ); + } + + @Override + public FetchStyle getFetchStyle() { + final String fetchSelection = pluralAttributeElement.getFetch() != null ? + pluralAttributeElement.getFetch().value() : + null; + final String outerJoinSelection = pluralAttributeElement.getOuterJoin() != null + ? pluralAttributeElement.getOuterJoin().value() + : null; + final int batchSize = Helper.getIntValue( pluralAttributeElement.getBatchSize(), -1 ); + + if ( fetchSelection == null ) { + if ( outerJoinSelection == null ) { + return batchSize > 1 ? FetchStyle.BATCH : FetchStyle.SELECT; + } + else { + if ( "auto".equals( outerJoinSelection ) ) { + return bindingContext().getMappingDefaults().areAssociationsLazy() + ? FetchStyle.SELECT + : FetchStyle.JOIN; + } + else { + return "true".equals( outerJoinSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT; + } + } + } + else { + if ( "subselect".equals( fetchSelection ) ) { + return FetchStyle.SUBSELECT; + } + else { + return "join".equals( fetchSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT; + } + } + } + @Override public FetchMode getFetchMode() { return pluralAttributeElement.getFetch() == null diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/ManyToOneAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/ManyToOneAttributeSourceImpl.java index 68236ef0c1..6af7d1bd70 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/ManyToOneAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/ManyToOneAttributeSourceImpl.java @@ -26,9 +26,12 @@ import java.util.List; import org.hibernate.FetchMode; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.mapping.PropertyGeneration; import org.hibernate.metamodel.source.LocalBindingContext; +import org.hibernate.metamodel.source.MappingException; import org.hibernate.metamodel.source.binder.ExplicitHibernateTypeSource; import org.hibernate.metamodel.source.binder.MetaAttributeSource; import org.hibernate.metamodel.source.binder.RelationalValueSource; @@ -131,6 +134,82 @@ public Iterable getCascadeStyles() { return Helper.interpretCascadeStyles( manyToOneElement.getCascade(), bindingContext ); } + @Override + public FetchTiming getFetchTiming() { + final String fetchSelection = manyToOneElement.getFetch() != null + ? manyToOneElement.getFetch().value() + : null; + final String lazySelection = manyToOneElement.getLazy() != null + ? manyToOneElement.getLazy().value() + : null; + final String outerJoinSelection = manyToOneElement.getOuterJoin() != null + ? manyToOneElement.getOuterJoin().value() + : null; + + if ( lazySelection == null ) { + if ( "join".equals( fetchSelection ) || "true".equals( outerJoinSelection ) ) { + return FetchTiming.IMMEDIATE; + } + else if ( "false".equals( outerJoinSelection ) ) { + return FetchTiming.DELAYED; + } + else { + return bindingContext.getMappingDefaults().areAssociationsLazy() + ? FetchTiming.DELAYED + : FetchTiming.IMMEDIATE; + } + } + else if ( "extra".equals( lazySelection ) ) { + return FetchTiming.EXTRA_LAZY; + } + else if ( "true".equals( lazySelection ) ) { + return FetchTiming.DELAYED; + } + else if ( "false".equals( lazySelection ) ) { + return FetchTiming.IMMEDIATE; + } + + throw new MappingException( + String.format( + "Unexpected lazy selection [%s] on '%s'", + lazySelection, + manyToOneElement.getName() + ), + bindingContext.getOrigin() + ); + } + + @Override + public FetchStyle getFetchStyle() { + // todo : handle batch fetches? + + final String fetchSelection = manyToOneElement.getFetch() != null + ? manyToOneElement.getFetch().value() + : null; + final String outerJoinSelection = manyToOneElement.getOuterJoin() != null + ? manyToOneElement.getOuterJoin().value() + : null; + + if ( fetchSelection == null ) { + if ( outerJoinSelection == null ) { + return FetchStyle.SELECT; + } + else { + if ( "auto".equals( outerJoinSelection ) ) { + return bindingContext.getMappingDefaults().areAssociationsLazy() + ? FetchStyle.SELECT + : FetchStyle.JOIN; + } + else { + return "true".equals( outerJoinSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT; + } + } + } + else { + return "join".equals( fetchSelection ) ? FetchStyle.JOIN : FetchStyle.SELECT; + } + } + @Override public FetchMode getFetchMode() { return manyToOneElement.getFetch() == null