HHH-7322 : Integrate one-to-many cascade and fetch mode to persisters

This commit is contained in:
Gail Badner 2012-06-06 12:42:55 -07:00
parent 92c7b2d04f
commit 503949b563
2 changed files with 153 additions and 99 deletions

View File

@ -99,6 +99,10 @@
import org.hibernate.metamodel.spi.binding.BasicAttributeBinding; import org.hibernate.metamodel.spi.binding.BasicAttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding; import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.Fetchable;
import org.hibernate.metamodel.spi.binding.PluralAttributeAssociationElementBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding; import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
@ -160,7 +164,7 @@ public abstract class AbstractEntityPersister
private final boolean hasSubselectLoadableCollections; private final boolean hasSubselectLoadableCollections;
protected final String rowIdName; protected final String rowIdName;
private final Set lazyProperties; private final Set<String> lazyProperties;
// The optional SQL string defined in the where attribute // The optional SQL string defined in the where attribute
private final String sqlWhereString; private final String sqlWhereString;
@ -566,13 +570,13 @@ public AbstractEntityPersister(
propertySelectable = new boolean[hydrateSpan]; propertySelectable = new boolean[hydrateSpan];
propertyColumnUpdateable = new boolean[hydrateSpan][]; propertyColumnUpdateable = new boolean[hydrateSpan][];
propertyColumnInsertable = new boolean[hydrateSpan][]; propertyColumnInsertable = new boolean[hydrateSpan][];
HashSet thisClassProperties = new HashSet(); Set<Property> thisClassProperties = new HashSet<Property>();
lazyProperties = new HashSet(); lazyProperties = new HashSet<String>();
ArrayList lazyNames = new ArrayList(); List<String> lazyNames = new ArrayList<String>();
ArrayList lazyNumbers = new ArrayList(); List<Integer> lazyNumbers = new ArrayList<Integer>();
ArrayList lazyTypes = new ArrayList(); List<Type> lazyTypes = new ArrayList<Type>();
ArrayList lazyColAliases = new ArrayList(); List<String[]> lazyColAliases = new ArrayList<String[]>();
iter = persistentClass.getPropertyClosureIterator(); iter = persistentClass.getPropertyClosureIterator();
i = 0; i = 0;
@ -865,13 +869,14 @@ public AbstractEntityPersister(
propertySelectable = new boolean[hydrateSpan]; propertySelectable = new boolean[hydrateSpan];
propertyColumnUpdateable = new boolean[hydrateSpan][]; propertyColumnUpdateable = new boolean[hydrateSpan][];
propertyColumnInsertable = new boolean[hydrateSpan][]; propertyColumnInsertable = new boolean[hydrateSpan][];
HashSet thisClassProperties = new HashSet(); Set<AttributeBinding> thisClassProperties = new HashSet<AttributeBinding>();
lazyProperties = new HashSet<String>();
List<String> lazyNames = new ArrayList<String>();
List<Integer> lazyNumbers = new ArrayList<Integer>();
List<Type> lazyTypes = new ArrayList<Type>();
List<String[]> lazyColAliases = new ArrayList<String[]>();
lazyProperties = new HashSet();
ArrayList lazyNames = new ArrayList();
ArrayList lazyNumbers = new ArrayList();
ArrayList lazyTypes = new ArrayList();
ArrayList lazyColAliases = new ArrayList();
i = 0; i = 0;
boolean foundFormula = false; boolean foundFormula = false;
@ -940,10 +945,7 @@ public AbstractEntityPersister(
lazyColAliases.add( colAliases ); lazyColAliases.add( colAliases );
} }
propertySelectable[i] = !attributeBinding.isBackRef();
// TODO: fix this when backrefs are working
//propertySelectable[i] = singularAttributeBinding.isBackRef();
propertySelectable[i] = true;
propertyUniqueness[i] = attributeBinding.isAlternateUniqueKey(); propertyUniqueness[i] = attributeBinding.isAlternateUniqueKey();
@ -987,21 +989,25 @@ public AbstractEntityPersister(
continue; continue;
} }
if ( ! attributeBinding.getAttribute().isSingular() ) { names.add( attributeBinding.getAttribute().getName() );
// collections handled separately classes.add( ( (EntityBinding) attributeBinding.getContainer() ).getEntity().getName() );
continue; boolean isDefinedBySubclass = ! thisClassProperties.contains( attributeBinding );
}
final SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding;
names.add( singularAttributeBinding.getAttribute().getName() );
classes.add( ( (EntityBinding) singularAttributeBinding.getContainer() ).getEntity().getName() );
boolean isDefinedBySubclass = ! thisClassProperties.contains( singularAttributeBinding );
definedBySubclass.add( isDefinedBySubclass ); definedBySubclass.add( isDefinedBySubclass );
propNullables.add( singularAttributeBinding.isNullable() || isDefinedBySubclass ); //TODO: is this completely correct? // TODOFix this when join tables are supported...
types.add( singularAttributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() ); //propNullables.add( attributeBinding.isOptional() || isDefinedBySubclass );
propNullables.add(
! attributeBinding.getAttribute().isSingular() ||
( (SingularAttributeBinding) attributeBinding).isNullable() ||
isDefinedBySubclass
);
types.add( attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() );
final int span = singularAttributeBinding.getRelationalValueBindings().size();
List<RelationalValueBinding> relationalValueBindings =
attributeBinding.getAttribute().isSingular() ?
( (SingularAttributeBinding) attributeBinding ).getRelationalValueBindings() :
null;
final int span = relationalValueBindings == null ? 0 : relationalValueBindings.size();
String[] cols = new String[ span ]; String[] cols = new String[ span ];
String[] readers = new String[ span ]; String[] readers = new String[ span ];
String[] readerTemplates = new String[ span ]; String[] readerTemplates = new String[ span ];
@ -1009,45 +1015,47 @@ public AbstractEntityPersister(
int[] colnos = new int[ span ]; int[] colnos = new int[ span ];
int[] formnos = new int[ span ]; int[] formnos = new int[ span ];
int l = 0; int l = 0;
Boolean lazy = singularAttributeBinding.isLazy() && lazyAvailable; Boolean lazy = attributeBinding.isLazy() && lazyAvailable;
for ( RelationalValueBinding valueBinding : singularAttributeBinding.getRelationalValueBindings() ) {
if ( valueBinding.isDerived() ) {
DerivedValue derivedValue = DerivedValue.class.cast( valueBinding.getValue() );
String template = getTemplateFromString( derivedValue.getExpression(), factory );
formnos[l] = formulaTemplates.size();
colnos[l] = -1;
formulaTemplates.add( template );
forms[l] = template;
formulas.add( derivedValue.getExpression() );
formulaAliases.add( derivedValue.getAlias( factory.getDialect(), null ) );
formulasLazy.add( lazy );
}
else {
org.hibernate.metamodel.spi.relational.Column col = org.hibernate.metamodel.spi.relational.Column.class.cast( valueBinding.getValue() );
String colName = col.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() );
colnos[l] = columns.size(); //before add :-)
formnos[l] = -1;
columns.add( colName );
cols[l] = colName;
aliases.add(
col.getAlias(
factory.getDialect(),
col.getTable()
)
);
columnsLazy.add( lazy );
// TODO: properties only selectable if they are non-plural???
columnSelectables.add( singularAttributeBinding.getAttribute().isSingular() );
readers[l] = if ( relationalValueBindings != null ) {
col.getReadFragment() == null ? for ( RelationalValueBinding valueBinding : relationalValueBindings ) {
col.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ) : if ( valueBinding.isDerived() ) {
col.getReadFragment(); DerivedValue derivedValue = DerivedValue.class.cast( valueBinding.getValue() );
String readerTemplate = getTemplateFromColumn( col, factory ); String template = getTemplateFromString( derivedValue.getExpression(), factory );
readerTemplates[l] = readerTemplate; formnos[l] = formulaTemplates.size();
columnReaderTemplates.add( readerTemplate ); colnos[l] = -1;
formulaTemplates.add( template );
forms[l] = template;
formulas.add( derivedValue.getExpression() );
formulaAliases.add( derivedValue.getAlias( factory.getDialect(), null ) );
formulasLazy.add( lazy );
}
else {
org.hibernate.metamodel.spi.relational.Column col = org.hibernate.metamodel.spi.relational.Column.class.cast( valueBinding.getValue() );
String colName = col.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() );
colnos[l] = columns.size(); //before add :-)
formnos[l] = -1;
columns.add( colName );
cols[l] = colName;
aliases.add(
col.getAlias(
factory.getDialect(),
col.getTable()
)
);
columnsLazy.add( lazy );
columnSelectables.add( ! attributeBinding.isBackRef() );
readers[l] =
col.getReadFragment() == null ?
col.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ) :
col.getReadFragment();
String readerTemplate = getTemplateFromColumn( col, factory );
readerTemplates[l] = readerTemplate;
columnReaderTemplates.add( readerTemplate );
}
l++;
} }
l++;
} }
propColumns.add( cols ); propColumns.add( cols );
propColumnReaders.add( readers ); propColumnReaders.add( readers );
@ -1056,14 +1064,26 @@ public AbstractEntityPersister(
propColumnNumbers.add( colnos ); propColumnNumbers.add( colnos );
propFormulaNumbers.add( formnos ); propFormulaNumbers.add( formnos );
if ( singularAttributeBinding.isAssociation() ) { CascadeStyle cascadeStyle = null;
SingularAssociationAttributeBinding associationAttributeBinding = if ( attributeBinding.isAssociation() ) {
(SingularAssociationAttributeBinding) singularAttributeBinding; if ( attributeBinding.getAttribute().isSingular() ) {
cascades.add( associationAttributeBinding.getCascadeStyle() ); cascadeStyle = ( ( SingularAssociationAttributeBinding) attributeBinding ).getCascadeStyle();
joinedFetchesList.add( associationAttributeBinding.getFetchMode() ); }
else {
PluralAttributeElementBinding pluralAttributeElementBinding =
( (PluralAttributeBinding) attributeBinding ).getPluralAttributeElementBinding();
cascadeStyle = ( (PluralAttributeAssociationElementBinding) pluralAttributeElementBinding).getCascadeStyle();
}
}
if ( cascadeStyle == null ) {
cascadeStyle = CascadeStyle.NONE;
}
cascades.add( cascadeStyle );
if ( attributeBinding instanceof Fetchable ) {
joinedFetchesList.add( ( (Fetchable) attributeBinding ).getFetchMode() );
} }
else { else {
cascades.add( CascadeStyle.NONE );
joinedFetchesList.add( FetchMode.SELECT ); joinedFetchesList.add( FetchMode.SELECT );
} }
} }
@ -1204,7 +1224,9 @@ private Object initializeLazyPropertiesFromDatastore(
final Serializable id, final Serializable id,
final EntityEntry entry) { final EntityEntry entry) {
if ( !hasLazyProperties() ) throw new AssertionFailure( "no lazy properties" ); if ( !hasLazyProperties() ) {
throw new AssertionFailure( "no lazy properties" );
}
LOG.trace( "Initializing lazy properties from datastore" ); LOG.trace( "Initializing lazy properties from datastore" );
@ -1673,9 +1695,13 @@ public Object forceVersionIncrement(Serializable id, Object currentVersion, Sess
} }
Object nextVersion = getVersionType().next( currentVersion, session ); Object nextVersion = getVersionType().next( currentVersion, session );
if (LOG.isTraceEnabled()) LOG.trace("Forcing version increment [" + MessageHelper.infoString(this, id, getFactory()) + "; " if ( LOG.isTraceEnabled() ) {
+ getVersionType().toLoggableString(currentVersion, getFactory()) + " -> " LOG.trace(
+ getVersionType().toLoggableString(nextVersion, getFactory()) + "]"); "Forcing version increment [" + MessageHelper.infoString( this, id, getFactory() ) + "; "
+ getVersionType().toLoggableString( currentVersion, getFactory() ) + " -> "
+ getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
);
}
// todo : cache this sql... // todo : cache this sql...
String versionIncrementString = generateVersionIncrementUpdateString(); String versionIncrementString = generateVersionIncrementUpdateString();
@ -2866,8 +2892,9 @@ protected void insert(
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Inserting entity: {0}", MessageHelper.infoString( this, id, getFactory() ) ); LOG.tracev( "Inserting entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
if ( j == 0 && isVersioned() ) if ( j == 0 && isVersioned() ) {
LOG.tracev( "Version: {0}", Versioning.getVersion( fields, this ) ); LOG.tracev( "Version: {0}", Versioning.getVersion( fields, this ) );
}
} }
// TODO : shouldn't inserts be Expectations.NONE? // TODO : shouldn't inserts be Expectations.NONE?
@ -3009,8 +3036,9 @@ protected boolean update(
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Updating entity: {0}", MessageHelper.infoString( this, id, getFactory() ) ); LOG.tracev( "Updating entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
if ( useVersion ) if ( useVersion ) {
LOG.tracev( "Existing version: {0} -> New version:{1}", oldVersion, fields[getVersionProperty()] ); LOG.tracev( "Existing version: {0} -> New version:{1}", oldVersion, fields[getVersionProperty()] );
}
} }
try { try {
@ -3127,8 +3155,9 @@ protected void delete(
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Deleting entity: {0}", MessageHelper.infoString( this, id, getFactory() ) ); LOG.tracev( "Deleting entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
if ( useVersion ) if ( useVersion ) {
LOG.tracev( "Version: {0}", version ); LOG.tracev( "Version: {0}", version );
}
} }
if ( isTableCascadeDeleteEnabled( j ) ) { if ( isTableCascadeDeleteEnabled( j ) ) {
@ -3434,24 +3463,50 @@ private String[] generateSQLDeletStrings(Object[] loadedState) {
protected void logStaticSQL() { protected void logStaticSQL() {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debugf("Static SQL for entity: %s", getEntityName()); LOG.debugf("Static SQL for entity: %s", getEntityName());
if (sqlLazySelectString != null) LOG.debugf(" Lazy select: %s", sqlLazySelectString); if ( sqlLazySelectString != null ) {
if (sqlVersionSelectString != null) LOG.debugf(" Version select: %s", sqlVersionSelectString); LOG.debugf( " Lazy select: %s", sqlLazySelectString );
if (sqlSnapshotSelectString != null) LOG.debugf(" Snapshot select: %s", sqlSnapshotSelectString); }
if ( sqlVersionSelectString != null ) {
LOG.debugf( " Version select: %s", sqlVersionSelectString );
}
if ( sqlSnapshotSelectString != null ) {
LOG.debugf( " Snapshot select: %s", sqlSnapshotSelectString );
}
for ( int j = 0; j < getTableSpan(); j++ ) { for ( int j = 0; j < getTableSpan(); j++ ) {
LOG.debugf(" Insert %s: %s", j, getSQLInsertStrings()[j]); LOG.debugf(" Insert %s: %s", j, getSQLInsertStrings()[j]);
LOG.debugf(" Update %s: %s", j, getSQLUpdateStrings()[j]); LOG.debugf(" Update %s: %s", j, getSQLUpdateStrings()[j]);
LOG.debugf(" Delete %s: %s", j, getSQLDeleteStrings()[j]); LOG.debugf(" Delete %s: %s", j, getSQLDeleteStrings()[j]);
} }
if (sqlIdentityInsertString != null) LOG.debugf(" Identity insert: %s", sqlIdentityInsertString); if ( sqlIdentityInsertString != null ) {
if (sqlUpdateByRowIdString != null) LOG.debugf(" Update by row id (all fields): %s", sqlUpdateByRowIdString); LOG.debugf( " Identity insert: %s", sqlIdentityInsertString );
if (sqlLazyUpdateByRowIdString != null) LOG.debugf(" Update by row id (non-lazy fields): %s", }
sqlLazyUpdateByRowIdString); if ( sqlUpdateByRowIdString != null ) {
if (sqlInsertGeneratedValuesSelectString != null) LOG.debugf("Insert-generated property select: %s", LOG.debugf( " Update by row id (all fields): %s", sqlUpdateByRowIdString );
sqlInsertGeneratedValuesSelectString); }
if (sqlUpdateGeneratedValuesSelectString != null) LOG.debugf("Update-generated property select: %s", if ( sqlLazyUpdateByRowIdString != null ) {
sqlUpdateGeneratedValuesSelectString); LOG.debugf(
if (sqlEntityIdByNaturalIdString != null) LOG.debugf("Id by Natural Id: %s", " Update by row id (non-lazy fields): %s",
sqlEntityIdByNaturalIdString); sqlLazyUpdateByRowIdString
);
}
if ( sqlInsertGeneratedValuesSelectString != null ) {
LOG.debugf(
"Insert-generated property select: %s",
sqlInsertGeneratedValuesSelectString
);
}
if ( sqlUpdateGeneratedValuesSelectString != null ) {
LOG.debugf(
"Update-generated property select: %s",
sqlUpdateGeneratedValuesSelectString
);
}
if ( sqlEntityIdByNaturalIdString != null ) {
LOG.debugf(
"Id by Natural Id: %s",
sqlEntityIdByNaturalIdString
);
}
} }
} }

View File

@ -129,13 +129,12 @@ protected ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idG
} }
private PropertyAccessor buildPropertyAccessor(AttributeBinding mappedProperty) { private PropertyAccessor buildPropertyAccessor(AttributeBinding mappedProperty) {
// TODO: fix when backrefs are working in new metamodel if ( mappedProperty.isBackRef() ) {
//if ( mappedProperty.isBackRef() ) { return PropertyAccessorFactory.getPropertyAccessor( null, mappedProperty.getPropertyAccessorName() );
// return mappedProperty.getPropertyAccessor( null ); }
//} else {
//else {
return PropertyAccessorFactory.getDynamicMapPropertyAccessor(); return PropertyAccessorFactory.getDynamicMapPropertyAccessor();
//} }
} }
/** /**