HHH-7240 - Develop identifier handling in new metamodel

This commit is contained in:
Steve Ebersole 2012-04-12 12:11:23 -05:00
parent a39b1a3a92
commit 5946391477
4 changed files with 79 additions and 45 deletions

View File

@ -23,6 +23,8 @@
*/
package org.hibernate.metamodel.spi.binding;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
@ -42,7 +44,7 @@ import org.hibernate.metamodel.spi.relational.Column;
public class EntityIdentifier {
private final EntityBinding entityBinding;
private BoundType boundType;
private List<SingularAttributeBinding> identifierAttributeBindings = new ArrayList<SingularAttributeBinding>();
private IdGenerator idGenerator;
private String unsavedValue;
@ -50,9 +52,7 @@ public class EntityIdentifier {
private Class idClassClass; // the class named in @IdClass
private IdentifierGenerator identifierGenerator;
private SingularNonAssociationAttributeBinding attributeBinding;
private List<SingularAttributeBinding> nonAggregatedCompositeAttributeBindings;
private int columnCount;
/**
* Create an identifier
@ -67,13 +67,11 @@ public class EntityIdentifier {
SingularNonAssociationAttributeBinding attributeBinding,
IdGenerator idGenerator,
String unsavedValue) {
if ( boundType != null ) {
throw new IllegalStateException( "Entity identifier was already bound" );
}
this.boundType = BoundType.SINGLE_ATTRIBUTE;
this.attributeBinding = attributeBinding;
ensureNotBound();
identifierAttributeBindings.add( attributeBinding );
this.idGenerator = idGenerator;
this.unsavedValue = unsavedValue;
this.columnCount = attributeBinding.getRelationalValueBindings().size();
// Configure primary key in relational model
for ( final RelationalValueBinding valueBinding : attributeBinding.getRelationalValueBindings() ) {
@ -81,23 +79,52 @@ public class EntityIdentifier {
}
}
private void ensureNotBound() {
if ( ! identifierAttributeBindings.isEmpty() ) {
throw new IllegalStateException( "Entity identifier was already bound" );
}
}
public void bindAsMultipleAttributeIdentifier(
List<SingularAttributeBinding> nonAggregatedCompositeAttributeBindings,
Class idClassClass) {
if ( boundType != null ) {
throw new IllegalStateException( "Entity identifier was already bound" );
ensureNotBound();
for ( SingularAttributeBinding attributeBinding : nonAggregatedCompositeAttributeBindings ) {
identifierAttributeBindings.add( attributeBinding );
columnCount += attributeBinding.getRelationalValueBindings().size();
// Configure primary key in relational model
for ( final RelationalValueBinding valueBinding : attributeBinding.getRelationalValueBindings() ) {
entityBinding.getPrimaryTable().getPrimaryKey().addColumn( (Column) valueBinding.getValue() );
}
}
this.boundType = BoundType.MULTIPLE_ATTRIBUTE;
this.nonAggregatedCompositeAttributeBindings = nonAggregatedCompositeAttributeBindings;
this.idClassClass = idClassClass;
}
public SingularNonAssociationAttributeBinding getValueBinding() {
return attributeBinding;
public boolean isSingleAttribute() {
ensureBound();
return identifierAttributeBindings.size() == 1;
}
public List<SingularAttributeBinding> getNonAggregatedCompositeAttributeBindings() {
return nonAggregatedCompositeAttributeBindings;
public List<SingularAttributeBinding> getIdentifierAttributeBindings() {
return Collections.unmodifiableList( identifierAttributeBindings );
}
public boolean isIdentifierAttributeBinding(AttributeBinding attributeBinding) {
for ( SingularAttributeBinding identifierAttributeBinding : identifierAttributeBindings ) {
if ( identifierAttributeBinding.equals( attributeBinding ) ) {
return true;
}
}
return false;
}
protected SingularNonAssociationAttributeBinding getSingleIdentifierAttributeBinding() {
if ( ! isSingleAttribute() ) {
throw new IllegalStateException( "Entity identifier is made up of multiple attributes" );
}
return (SingularNonAssociationAttributeBinding) identifierAttributeBindings.get( 0 );
}
public String getUnsavedValue() {
@ -105,7 +132,7 @@ public class EntityIdentifier {
}
public boolean isEmbedded() {
return boundType == BoundType.SINGLE_ATTRIBUTE && attributeBinding.getRelationalValueBindings().size() > 1;
return isSingleAttribute() && columnCount > 1;
}
public Class getIdClassClass() {
@ -113,25 +140,39 @@ public class EntityIdentifier {
}
public boolean isIdentifierMapper() {
// i think
return boundType == BoundType.MULTIPLE_ATTRIBUTE && idClassClass != null;
// i think this is the intended check for this method
return ! isSingleAttribute() && idClassClass != null;
}
// todo do we really need this createIdentifierGenerator and how do we make sure the getter is not called too early
// maybe some sort of visitor pattern here!? (HF)
public IdentifierGenerator createIdentifierGenerator(IdentifierGeneratorFactory factory, Properties properties) {
if ( idGenerator != null ) {
identifierGenerator = attributeBinding.createIdentifierGenerator( idGenerator, factory, properties );
ensureBound();
if ( identifierGenerator == null ) {
if ( isSingleAttribute() && idGenerator != null ) {
identifierGenerator = getSingleIdentifierAttributeBinding().createIdentifierGenerator(
idGenerator,
factory,
properties
);
}
}
return identifierGenerator;
}
public IdentifierGenerator getIdentifierGenerator() {
ensureBound();
return identifierGenerator;
}
private static enum BoundType {
SINGLE_ATTRIBUTE,
MULTIPLE_ATTRIBUTE
protected void ensureBound() {
if ( identifierAttributeBindings.isEmpty() ) {
throw new IllegalStateException( "Entity identifier was not yet bound" );
}
}
public int getColumnCount() {
ensureBound();
return columnCount;
}
}

View File

@ -775,14 +775,11 @@ public abstract class AbstractEntityPersister
final SessionFactoryImplementor factory) throws HibernateException {
this.factory = factory;
this.cacheAccessStrategy = cacheAccessStrategy;
this.isLazyPropertiesCacheable =
entityBinding.getHierarchyDetails().getCaching() == null ?
false :
entityBinding.getHierarchyDetails().getCaching().isCacheLazyProperties();
this.cacheEntryStructure =
factory.getSettings().isStructuredCacheEntriesEnabled() ?
new StructuredCacheEntry(this) :
new UnstructuredCacheEntry();
this.isLazyPropertiesCacheable = entityBinding.getHierarchyDetails().getCaching() != null
&& entityBinding.getHierarchyDetails().getCaching().isCacheLazyProperties();
this.cacheEntryStructure = factory.getSettings().isStructuredCacheEntriesEnabled()
? new StructuredCacheEntry(this)
: new UnstructuredCacheEntry();
this.entityMetamodel = new EntityMetamodel( entityBinding, factory );
this.entityTuplizer = this.entityMetamodel.getTuplizer();
int batch = entityBinding.getBatchSize();
@ -791,24 +788,20 @@ public abstract class AbstractEntityPersister
}
batchSize = batch;
hasSubselectLoadableCollections = entityBinding.hasSubselectLoadableCollections();
rowIdName = entityBinding.getRowId();
loaderName = entityBinding.getCustomLoaderName();
propertyMapping = new BasicEntityPropertyMapping( this );
// IDENTIFIER
identifierColumnSpan = entityBinding.getHierarchyDetails()
.getEntityIdentifier()
.getValueBinding()
.getRelationalValueBindings()
.size();
identifierColumnSpan = entityBinding.getHierarchyDetails().getEntityIdentifier().getColumnCount();
rootTableKeyColumnNames = new String[identifierColumnSpan];
rootTableKeyColumnReaders = new String[identifierColumnSpan];
rootTableKeyColumnReaderTemplates = new String[identifierColumnSpan];
identifierAliases = new String[identifierColumnSpan];
rowIdName = entityBinding.getRowId();
loaderName = entityBinding.getCustomLoaderName();
int i = 0;
for ( org.hibernate.metamodel.spi.relational.Column col : entityBinding.getPrimaryTable().getPrimaryKey().getColumns() ) {
@ -882,7 +875,7 @@ public abstract class AbstractEntityPersister
i = 0;
boolean foundFormula = false;
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
// entity identifier is not considered a "normal" property
continue;
}
@ -985,7 +978,7 @@ public abstract class AbstractEntityPersister
List<Boolean> propNullables = new ArrayList<Boolean>();
for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) {
if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
// entity identifier is not considered a "normal" property
continue;
}

View File

@ -619,7 +619,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
for( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
// TODO: fix when joins are working (HHH-6391)
//propertyTableNumbers[i++] = entityBinding.getJoinNumber( attributeBinding);
if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
continue; // skip identifier binding
}
if ( ! attributeBinding.getAttribute().isSingular() ) {

View File

@ -426,7 +426,7 @@ public class EntityMetamodel implements Serializable {
boolean foundUpdateableNaturalIdProperty = false;
for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) {
if ( attributeBinding == rootEntityIdentifier ) {
if ( entityBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding( attributeBinding ) ) {
// skip the identifier attribute binding
continue;
}