HHH-7736 partial joined subclass support

This commit is contained in:
Strong Liu 2012-11-15 19:54:51 +08:00
parent 4359b9971b
commit e998269402
20 changed files with 386 additions and 194 deletions

View File

@ -26,9 +26,34 @@ package org.hibernate.cache.spi.entry;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
/** /**
* {@link CacheEntry} structure, used for construct / deconstruct the cache entry to different format that store in the 2LC.
*
* @author Gavin King * @author Gavin King
*/ */
public interface CacheEntryStructure { public interface CacheEntryStructure<S,T> {
public Object structure(Object item); /**
public Object destructure(Object map, SessionFactoryImplementor factory); * Convert the giving {@param source} to the target format of {@link T}.
* <br>
* The generic type of {@link S} should be either of :
* <ul>
* <li>{@link CacheEntry}</li>
* <li>{@link CollectionCacheEntry}</li>
* </ul>
* </br>
*
* This is called just before cache entry being stored into 2LC.
*
* @param source The raw cache entry.
* @return The target type of value that being persisted into 2LC.
*/
public T structure(S source);
/**
* Deconstruct the {@param target} that load from 2LC to its source type of {@link S}.
*
* @param target The item that load from the 2LC.
* @param factory The SessionFactoryImplementor.
* @return The source type of cache entry.
*/
public S destructure(T target, SessionFactoryImplementor factory);
} }

View File

@ -33,36 +33,36 @@ import org.hibernate.persister.entity.EntityPersister;
/** /**
* @author Gavin King * @author Gavin King
*/ */
public class StructuredCacheEntry implements CacheEntryStructure { public class StructuredCacheEntry implements CacheEntryStructure<CacheEntry, Map> {
private EntityPersister persister; private final EntityPersister persister;
public StructuredCacheEntry(EntityPersister persister) { public StructuredCacheEntry(EntityPersister persister) {
this.persister = persister; this.persister = persister;
} }
public Object destructure(Object item, SessionFactoryImplementor factory) { @Override
Map map = (Map) item; public CacheEntry destructure(Map map, SessionFactoryImplementor factory) {
boolean lazyPropertiesUnfetched = ( (Boolean) map.get("_lazyPropertiesUnfetched") ).booleanValue(); boolean lazyPropertiesUnfetched = ( (Boolean) map.get( "_lazyPropertiesUnfetched" ) ).booleanValue();
String subclass = (String) map.get("_subclass"); String subclass = (String) map.get( "_subclass" );
Object version = map.get("_version"); Object version = map.get( "_version" );
EntityPersister subclassPersister = factory.getEntityPersister(subclass); EntityPersister subclassPersister = factory.getEntityPersister( subclass );
String[] names = subclassPersister.getPropertyNames(); String[] names = subclassPersister.getPropertyNames();
Serializable[] state = new Serializable[names.length]; Serializable[] state = new Serializable[names.length];
for ( int i=0; i<names.length; i++ ) { for ( int i = 0; i < names.length; i++ ) {
state[i] = (Serializable) map.get( names[i] ); state[i] = (Serializable) map.get( names[i] );
} }
return new CacheEntry(state, subclass, lazyPropertiesUnfetched, version); return new CacheEntry( state, subclass, lazyPropertiesUnfetched, version );
} }
public Object structure(Object item) { @Override
CacheEntry entry = (CacheEntry) item; public Map structure(CacheEntry entry) {
String[] names = persister.getPropertyNames(); String[] names = persister.getPropertyNames();
Map map = new HashMap(names.length+2); Map map = new HashMap( names.length + 3 );
map.put( "_subclass", entry.getSubclass() ); map.put( "_subclass", entry.getSubclass() );
map.put( "_version", entry.getVersion() ); map.put( "_version", entry.getVersion() );
map.put( "_lazyPropertiesUnfetched", entry.areLazyPropertiesUnfetched() ); map.put( "_lazyPropertiesUnfetched", entry.areLazyPropertiesUnfetched() );
for ( int i=0; i<names.length; i++ ) { for ( int i = 0; i < names.length; i++ ) {
map.put( names[i], entry.getDisassembledState()[i] ); map.put( names[i], entry.getDisassembledState()[i] );
} }
return map; return map;

View File

@ -30,17 +30,19 @@ import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
/** /**
* For other plural attributes except map, this impl is used.
* </br>
* Internally, a list that contains all collection states is stored into 2LC.
*
* @author Gavin King * @author Gavin King
*/ */
public class StructuredCollectionCacheEntry implements CacheEntryStructure { public class StructuredCollectionCacheEntry implements CacheEntryStructure<CollectionCacheEntry, List<Serializable>> {
@Override
public Object structure(Object item) { public List<Serializable> structure(CollectionCacheEntry entry) {
CollectionCacheEntry entry = (CollectionCacheEntry) item;
return Arrays.asList( entry.getState() ); return Arrays.asList( entry.getState() );
} }
@Override
public Object destructure(Object item, SessionFactoryImplementor factory) { public CollectionCacheEntry destructure(List<Serializable> list, SessionFactoryImplementor factory) {
List list = (List) item;
return new CollectionCacheEntry( list.toArray( new Serializable[list.size()] ) ); return new CollectionCacheEntry( list.toArray( new Serializable[list.size()] ) );
} }

View File

@ -31,31 +31,30 @@ import java.util.Map;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
/** /**
* (De)structure the map type collection attribute that is being cached into 2LC.
*
* @author Gavin King * @author Gavin King
*/ */
public class StructuredMapCacheEntry implements CacheEntryStructure { public class StructuredMapCacheEntry implements CacheEntryStructure<CollectionCacheEntry, Map<Serializable,Serializable>> {
@Override
public Object structure(Object item) { public Map<Serializable, Serializable> structure(CollectionCacheEntry entry) {
CollectionCacheEntry entry = (CollectionCacheEntry) item; final Serializable[] states = entry.getState();
Serializable[] state = entry.getState(); final Map<Serializable, Serializable> map = new HashMap<Serializable, Serializable>( states.length );
Map map = new HashMap(state.length); for ( final Serializable state : states ) {
for ( int i=0; i<state.length; ) { map.put( state, state );
map.put( state[i++], state[i++] );
} }
return map; return map;
} }
public Object destructure(Object item, SessionFactoryImplementor factory) { @Override
Map map = (Map) item; public CollectionCacheEntry destructure(Map<Serializable, Serializable> map, SessionFactoryImplementor factory) {
Serializable[] state = new Serializable[ map.size()*2 ]; Serializable[] states = new Serializable[map.size() * 2];
int i=0; int i = 0;
Iterator iter = map.entrySet().iterator(); for ( final Serializable key : map.keySet() ) {
while ( iter.hasNext() ) { states[i++] = key;
Map.Entry me = (Map.Entry) iter.next(); states[i++] = map.get( key );
state[i++] = (Serializable) me.getKey();
state[i++] = (Serializable) me.getValue();
} }
return new CollectionCacheEntry(state); return new CollectionCacheEntry( states );
} }
} }

View File

@ -26,14 +26,23 @@ package org.hibernate.cache.spi.entry;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
/** /**
* The very simple implementation of {@code CacheEntryStructure} that doing nothing but just return what it get.
*
* </br>
*
* This is used when {@link org.hibernate.cfg.AvailableSettings#USE_STRUCTURED_CACHE} is set to {@code false}.
*
* NOTE: This property is set to {@code false} by default.
*
* @author Gavin King * @author Gavin King
*/ */
public class UnstructuredCacheEntry implements CacheEntryStructure { public class UnstructuredCacheEntry implements CacheEntryStructure<Object, Object> {
@Override
public Object structure(Object item) { public Object structure(Object item) {
return item; return item;
} }
@Override
public Object destructure(Object map, SessionFactoryImplementor factory) { public Object destructure(Object map, SessionFactoryImplementor factory) {
return map; return map;
} }

View File

@ -36,33 +36,33 @@ import java.util.List;
* invoke the Iterators in sequence until all Iterators are exhausted. * invoke the Iterators in sequence until all Iterators are exhausted.
* *
*/ */
public class JoinedIterator implements Iterator { public class JoinedIterator<T> implements Iterator<T> {
private static final Iterator[] ITERATORS = {}; private static final Iterator[] ITERATORS = {};
// wrapped iterators // wrapped iterators
private Iterator[] iterators; private Iterator<T>[] iterators;
// index of current iterator in the wrapped iterators array // index of current iterator in the wrapped iterators array
private int currentIteratorIndex; private int currentIteratorIndex;
// the current iterator // the current iterator
private Iterator currentIterator; private Iterator<T> currentIterator;
// the last used iterator // the last used iterator
private Iterator lastUsedIterator; private Iterator<T> lastUsedIterator;
public JoinedIterator(List iterators) { public JoinedIterator(List<Iterator<T>> iterators) {
this( (Iterator[]) iterators.toArray(ITERATORS) ); this( iterators.toArray(ITERATORS) );
} }
public JoinedIterator(Iterator[] iterators) { public JoinedIterator(Iterator<T>[] iterators) {
if( iterators==null ) if( iterators==null )
throw new NullPointerException("Unexpected NULL iterators argument"); throw new NullPointerException("Unexpected NULL iterators argument");
this.iterators = iterators; this.iterators = iterators;
} }
public JoinedIterator(Iterator first, Iterator second) { public JoinedIterator(Iterator<T> first, Iterator<T> second) {
this( new Iterator[] { first, second } ); this( new Iterator[] { first, second } );
} }
@ -71,7 +71,7 @@ public class JoinedIterator implements Iterator {
return currentIterator.hasNext(); return currentIterator.hasNext();
} }
public Object next() { public T next() {
updateCurrentIterator(); updateCurrentIterator();
return currentIterator.next(); return currentIterator.next();
} }

View File

@ -29,17 +29,17 @@ import java.util.Iterator;
/** /**
* @author Gavin King * @author Gavin King
*/ */
public final class SingletonIterator implements Iterator { public final class SingletonIterator<T> implements Iterator<T> {
private Object value; private T value;
private boolean hasNext = true; private boolean hasNext = true;
public boolean hasNext() { public boolean hasNext() {
return hasNext; return hasNext;
} }
public Object next() { public T next() {
if (hasNext) { if ( hasNext ) {
hasNext = false; hasNext = false;
return value; return value;
} }
@ -52,7 +52,7 @@ public final class SingletonIterator implements Iterator {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public SingletonIterator(Object value) { public SingletonIterator(T value) {
this.value = value; this.value = value;
} }

View File

@ -54,6 +54,7 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder; import org.hibernate.internal.util.ValueHolder;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.internal.HibernateTypeHelper.ReflectedCollectionJavaTypes; import org.hibernate.metamodel.internal.HibernateTypeHelper.ReflectedCollectionJavaTypes;
import org.hibernate.metamodel.spi.MetadataImplementor; import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding; import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding;
@ -133,6 +134,7 @@ import org.hibernate.metamodel.spi.source.PluralAttributeElementSource;
import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource; import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource;
import org.hibernate.metamodel.spi.source.PluralAttributeKeySource; import org.hibernate.metamodel.spi.source.PluralAttributeKeySource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource; import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource; import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.RelationalValueSourceContainer; import org.hibernate.metamodel.spi.source.RelationalValueSourceContainer;
import org.hibernate.metamodel.spi.source.RootEntitySource; import org.hibernate.metamodel.spi.source.RootEntitySource;
@ -158,7 +160,7 @@ import org.jboss.logging.Logger;
/** /**
* The common binder shared between annotations and {@code hbm.xml} processing. * The common binder shared between annotations and {@code hbm.xml} processing.
* <p/> * <p/>
* The API consists of {@link #Binder(org.hibernate.metamodel.spi.MetadataImplementor, IdentifierGeneratorFactory)} and {@link #bindEntities(Iterable)} * The API consists of {@link #Binder(org.hibernate.metamodel.spi.MetadataImplementor, IdentifierGeneratorFactory)} and {@link #bindEntityHierarchies}
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Hardy Ferentschik * @author Hardy Ferentschik
@ -270,7 +272,7 @@ public class Binder {
private AttributeBinding attributeBinding( final String entityName, final String attributeName ) { private AttributeBinding attributeBinding( final String entityName, final String attributeName ) {
// Check if binding has already been created // Check if binding has already been created
final EntityBinding entityBinding = entityBinding( entityName ); final EntityBinding entityBinding = findOrBindingEntityBinding( entityName );
final AttributeSource attributeSource = attributeSourcesByName.get( attributeSourcesByNameKey( entityName, attributeName ) ); final AttributeSource attributeSource = attributeSourcesByName.get( attributeSourcesByNameKey( entityName, attributeName ) );
bindAttribute( entityBinding, attributeSource ); bindAttribute( entityBinding, attributeSource );
return entityBinding.locateAttributeBinding( attributeName ); return entityBinding.locateAttributeBinding( attributeName );
@ -772,21 +774,100 @@ public class Binder {
typeHelper.bindJdbcDataType( resolvedType, value ); typeHelper.bindJdbcDataType( resolvedType, value );
} }
private EntityBinding bindEntities( final EntityHierarchy entityHierarchy ) { private EntityBinding bindSubEntity(final EntitySource entitySource, final EntityBinding superEntityBinding) {
// Return existing binding if available
EntityBinding entityBinding = metadata.getEntityBinding( entitySource.getEntityName() );
if ( entityBinding != null ) {
return entityBinding;
}
final LocalBindingContext bindingContext = entitySource.getLocalBindingContext();
bindingContexts.push( bindingContext );
try {
// Create new entity binding
entityBinding = createEntityBinding( entitySource, superEntityBinding );
entityBinding.setMutable( entityBinding.getHierarchyDetails().getRootEntityBinding().isMutable() );
bindPrimaryTable( entityBinding, entitySource );
bindSubEntityPrimaryKey( entityBinding, entitySource );
bindSecondaryTables( entityBinding, entitySource );
bindUniqueConstraints( entityBinding, entitySource );
bindAttributes( entityBinding, entitySource );
bindSubEntities( entityBinding, entitySource );
return entityBinding;
} finally {
bindingContexts.pop();
}
}
private void bindSubEntityPrimaryKey(final EntityBinding entityBinding, final EntitySource entitySource) {
final InheritanceType inheritanceType = entityBinding.getHierarchyDetails().getInheritanceType();
final EntityBinding superEntityBinding = entityBinding.getSuperEntityBinding();
if ( superEntityBinding == null ) {
throw new AssertionFailure( "super entitybinding is null " );
}
if ( inheritanceType == InheritanceType.JOINED ) {
SubclassEntitySource subclassEntitySource = (SubclassEntitySource) entitySource;
ForeignKey fk = entityBinding.getPrimaryTable().createForeignKey(
superEntityBinding.getPrimaryTable(),
subclassEntitySource.getJoinedForeignKeyName()
);
final List<PrimaryKeyJoinColumnSource> primaryKeyJoinColumnSources = subclassEntitySource.getPrimaryKeyJoinColumnSources();
final boolean hasPrimaryKeyJoinColumns = CollectionHelper.isNotEmpty( primaryKeyJoinColumnSources );
final List<Column> superEntityBindingPrimaryKeyColumns = superEntityBinding.getPrimaryTable().getPrimaryKey().getColumns();
for ( int i = 0; i < superEntityBindingPrimaryKeyColumns.size(); i++ ) {
Column superEntityBindingPrimaryKeyColumn = superEntityBindingPrimaryKeyColumns.get( i );
PrimaryKeyJoinColumnSource primaryKeyJoinColumnSource = hasPrimaryKeyJoinColumns && i < primaryKeyJoinColumnSources
.size() ? primaryKeyJoinColumnSources.get( i ) : null;
final String columnName;
if ( primaryKeyJoinColumnSource != null && StringHelper.isNotEmpty( primaryKeyJoinColumnSource.getColumnName() ) ) {
columnName = bindingContext().getNamingStrategy().columnName( primaryKeyJoinColumnSource.getColumnName() );
} else {
columnName = superEntityBindingPrimaryKeyColumn.getColumnName().getText();
}
Column column = entityBinding.getPrimaryTable().locateOrCreateColumn( columnName );
column.setCheckCondition( superEntityBindingPrimaryKeyColumn.getCheckCondition() );
column.setComment( superEntityBindingPrimaryKeyColumn.getComment() );
column.setDefaultValue( superEntityBindingPrimaryKeyColumn.getDefaultValue() );
column.setIdentity( superEntityBindingPrimaryKeyColumn.isIdentity() );
column.setNullable( superEntityBindingPrimaryKeyColumn.isNullable() );
column.setReadFragment( superEntityBindingPrimaryKeyColumn.getReadFragment() );
column.setWriteFragment( superEntityBindingPrimaryKeyColumn.getWriteFragment() );
column.setUnique( superEntityBindingPrimaryKeyColumn.isUnique() );
final String sqlType;
if(primaryKeyJoinColumnSource!=null && StringHelper.isNotEmpty( primaryKeyJoinColumnSource.getColumnDefinition() )){
sqlType = primaryKeyJoinColumnSource.getColumnDefinition();
} else {
sqlType = superEntityBindingPrimaryKeyColumn.getSqlType();
}
column.setSqlType( sqlType );
column.setSize( superEntityBindingPrimaryKeyColumn.getSize() );
column.setJdbcDataType( superEntityBindingPrimaryKeyColumn.getJdbcDataType() );
entityBinding.getPrimaryTable().getPrimaryKey().addColumn( column );
//todo still need to figure out how to handle the referencedColumnName property
fk.addColumnMapping( column, superEntityBindingPrimaryKeyColumn );
}
}
}
/**
* Binding a single entity hierarchy.
*
* @param entityHierarchy The entity hierarchy to be binded.
*
* @return The root {@link EntityBinding} of the entity hierarchy mapping.
*/
private EntityBinding bindEntityHierarchy(final EntityHierarchy entityHierarchy) {
final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource(); final RootEntitySource rootEntitySource = entityHierarchy.getRootEntitySource();
// Return existing binding if available // Return existing binding if available
EntityBinding rootEntityBinding = metadata.getEntityBinding( rootEntitySource.getEntityName() ); EntityBinding rootEntityBinding = metadata.getEntityBinding( rootEntitySource.getEntityName() );
if ( rootEntityBinding != null ) { if ( rootEntityBinding != null ) {
return rootEntityBinding; return rootEntityBinding;
} }
// Save inheritance type and entity mode that will apply to entire hierarchy setupBindingContext( entityHierarchy, rootEntitySource );
inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() );
entityModes.push( rootEntitySource.getEntityMode() );
final LocalBindingContext bindingContext = rootEntitySource.getLocalBindingContext();
bindingContexts.push( bindingContext );
try { try {
// Create root entity binding // Create root entity binding
rootEntityBinding = createEntityBinding( rootEntitySource, null ); rootEntityBinding = createEntityBinding( rootEntitySource, null );
bindPrimaryTable( rootEntityBinding, rootEntitySource );
// Create/Bind root-specific information // Create/Bind root-specific information
bindIdentifier( rootEntityBinding, rootEntitySource.getIdentifierSource() ); bindIdentifier( rootEntityBinding, rootEntitySource.getIdentifierSource() );
bindSecondaryTables( rootEntityBinding, rootEntitySource ); bindSecondaryTables( rootEntityBinding, rootEntitySource );
@ -808,14 +889,30 @@ public class Binder {
bindSubEntities( rootEntityBinding, rootEntitySource ); bindSubEntities( rootEntityBinding, rootEntitySource );
} }
} finally { } finally {
bindingContexts.pop(); cleanupBindingContext();
inheritanceTypes.pop();
entityModes.pop();
} }
return rootEntityBinding; return rootEntityBinding;
} }
public void bindEntities( final Iterable< EntityHierarchy > entityHierarchies ) { private void cleanupBindingContext() {
bindingContexts.pop();
inheritanceTypes.pop();
entityModes.pop();
}
private void setupBindingContext(EntityHierarchy entityHierarchy, RootEntitySource rootEntitySource) {
// Save inheritance type and entity mode that will apply to entire hierarchy
inheritanceTypes.push( entityHierarchy.getHierarchyInheritanceType() );
entityModes.push( rootEntitySource.getEntityMode() );
bindingContexts.push( rootEntitySource.getLocalBindingContext() );
}
/**
* The entry point of {@linkplain Binder} class, binds all the entity hierarchy one by one.
*
* @param entityHierarchies The entity hierarchies resolved from mappings
*/
public void bindEntityHierarchies(final Iterable<EntityHierarchy> entityHierarchies) {
entitySourcesByName.clear(); entitySourcesByName.clear();
attributeSourcesByName.clear(); attributeSourcesByName.clear();
inheritanceTypes.clear(); inheritanceTypes.clear();
@ -829,29 +926,7 @@ public class Binder {
} }
// Bind each entity hierarchy // Bind each entity hierarchy
for ( final EntityHierarchy entityHierarchy : entityHierarchies ) { for ( final EntityHierarchy entityHierarchy : entityHierarchies ) {
bindEntities( entityHierarchy ); bindEntityHierarchy( entityHierarchy );
}
}
private EntityBinding bindEntity( final EntitySource entitySource, final EntityBinding superEntityBinding ) {
// Return existing binding if available
EntityBinding entityBinding = metadata.getEntityBinding( entitySource.getEntityName() );
if ( entityBinding != null ) {
return entityBinding;
}
final LocalBindingContext bindingContext = entitySource.getLocalBindingContext();
bindingContexts.push( bindingContext );
try {
// Create new entity binding
entityBinding = createEntityBinding( entitySource, superEntityBinding );
entityBinding.setMutable( entityBinding.getHierarchyDetails().getRootEntityBinding().isMutable() );
bindSecondaryTables( entityBinding, entitySource );
bindUniqueConstraints( entityBinding, entitySource );
bindAttributes( entityBinding, entitySource );
bindSubEntities( entityBinding, entitySource );
return entityBinding;
} finally {
bindingContexts.pop();
} }
} }
@ -1122,7 +1197,7 @@ public class Binder {
bindingContext().qualifyClassName( attributeSource.getReferencedEntityName() != null bindingContext().qualifyClassName( attributeSource.getReferencedEntityName() != null
? attributeSource.getReferencedEntityName() ? attributeSource.getReferencedEntityName()
: referencedJavaTypeValue.getValue().getName() ); : referencedJavaTypeValue.getValue().getName() );
final EntityBinding referencedEntityBinding = entityBinding( referencedEntityName ); final EntityBinding referencedEntityBinding = findOrBindingEntityBinding( referencedEntityName );
//now find the referenced attribute binding, either the referenced entity's id attribute or the referenced attribute //now find the referenced attribute binding, either the referenced entity's id attribute or the referenced attribute
//todo referenced entityBinding null check? //todo referenced entityBinding null check?
// Foreign key... // Foreign key...
@ -1528,7 +1603,7 @@ public class Binder {
createAttributePath( attributeBinding ) createAttributePath( attributeBinding )
) ); ) );
} }
EntityBinding referencedEntityBinding = entityBinding( referencedEntityName ); EntityBinding referencedEntityBinding = findOrBindingEntityBinding( referencedEntityName );
bindOneToManyCollectionKey( attributeBinding, attributeSource, referencedEntityBinding ); bindOneToManyCollectionKey( attributeBinding, attributeSource, referencedEntityBinding );
bindOneToManyCollectionElement( bindOneToManyCollectionElement(
(OneToManyPluralAttributeElementBinding) attributeBinding.getPluralAttributeElementBinding(), (OneToManyPluralAttributeElementBinding) attributeBinding.getPluralAttributeElementBinding(),
@ -1563,21 +1638,37 @@ public class Binder {
return attributeBinding; return attributeBinding;
} }
private void bindPrimaryTable( final EntityBinding entityBinding, final EntitySource entitySource ) { private void bindPrimaryTable(final EntityBinding entityBinding, final EntitySource entitySource) {
final TableSpecification table = createTable( final EntityBinding superEntityBinding = entityBinding.getSuperEntityBinding();
entitySource.getPrimaryTable(), new DefaultNamingStrategy() { final InheritanceType inheritanceType = entityBinding.getHierarchyDetails().getInheritanceType();
final TableSpecification table;
@Override final String tableName;
public String defaultName() { if ( superEntityBinding != null && inheritanceType == InheritanceType.SINGLE_TABLE ) {
String name = StringHelper.isNotEmpty( entityBinding.getJpaEntityName() ) ? entityBinding.getJpaEntityName() : entityBinding table = superEntityBinding.getPrimaryTable();
.getEntity() tableName = superEntityBinding.getPrimaryTableName();
.getClassName(); // Configure discriminator if present
return bindingContexts.peek().getNamingStrategy().classToTableName( name ); final String discriminatorValue = entitySource.getDiscriminatorMatchValue() != null ?
} entitySource.getDiscriminatorMatchValue()
: entitySource.getEntityName();
entityBinding.setDiscriminatorMatchValue( discriminatorValue );
}
else {
table = createTable(
entitySource.getPrimaryTable(), new DefaultNamingStrategy() {
@Override
public String defaultName() {
String name = StringHelper.isNotEmpty( entityBinding.getJpaEntityName() ) ? entityBinding.getJpaEntityName() : entityBinding
.getEntity()
.getClassName();
return bindingContexts.peek().getNamingStrategy().classToTableName( name );
}
}
);
tableName = table.getLogicalName().getText();
} }
);
entityBinding.setPrimaryTable( table ); entityBinding.setPrimaryTable( table );
entityBinding.setPrimaryTableName( table.getLogicalName().getText() ); entityBinding.setPrimaryTableName( tableName );
} }
private void bindSecondaryTables( final EntityBinding entityBinding, final EntitySource entitySource ) { private void bindSecondaryTables( final EntityBinding entityBinding, final EntitySource entitySource ) {
@ -1727,7 +1818,7 @@ public class Binder {
private void bindSubEntities( final EntityBinding entityBinding, final EntitySource entitySource ) { private void bindSubEntities( final EntityBinding entityBinding, final EntitySource entitySource ) {
for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) { for ( final SubclassEntitySource subEntitySource : entitySource.subclassEntitySources() ) {
bindEntity( subEntitySource, entityBinding ); bindSubEntity( subEntitySource, entityBinding );
} }
} }
@ -1954,6 +2045,7 @@ public class Binder {
entityClassName, entityClassName,
bindingContext.makeClassReference( entityClassName ), bindingContext.makeClassReference( entityClassName ),
superEntityBinding == null ? null : superEntityBinding.getEntity() ) ); superEntityBinding == null ? null : superEntityBinding.getEntity() ) );
entityBinding.setEntityName( entitySource.getEntityName() ); entityBinding.setEntityName( entitySource.getEntityName() );
entityBinding.setJpaEntityName( entitySource.getJpaEntityName() ); //must before creating primary table entityBinding.setJpaEntityName( entitySource.getJpaEntityName() ); //must before creating primary table
entityBinding.setDynamicUpdate( entitySource.isDynamicUpdate() ); entityBinding.setDynamicUpdate( entitySource.isDynamicUpdate() );
@ -1961,39 +2053,11 @@ public class Binder {
entityBinding.setBatchSize( entitySource.getBatchSize() ); entityBinding.setBatchSize( entitySource.getBatchSize() );
entityBinding.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() ); entityBinding.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() );
entityBinding.setAbstract( entitySource.isAbstract() ); entityBinding.setAbstract( entitySource.isAbstract() );
entityBinding.setCustomLoaderName( entitySource.getCustomLoaderName() ); entityBinding.setCustomLoaderName( entitySource.getCustomLoaderName() );
entityBinding.setCustomInsert( entitySource.getCustomSqlInsert() ); entityBinding.setCustomInsert( entitySource.getCustomSqlInsert() );
entityBinding.setCustomUpdate( entitySource.getCustomSqlUpdate() ); entityBinding.setCustomUpdate( entitySource.getCustomSqlUpdate() );
entityBinding.setCustomDelete( entitySource.getCustomSqlDelete() ); entityBinding.setCustomDelete( entitySource.getCustomSqlDelete() );
entityBinding.setJpaCallbackClasses( entitySource.getJpaCallbackClasses() ); entityBinding.setJpaCallbackClasses( entitySource.getJpaCallbackClasses() );
// Create relational table
if ( superEntityBinding != null && inheritanceType == InheritanceType.SINGLE_TABLE ) {
entityBinding.setPrimaryTable( superEntityBinding.getPrimaryTable() );
entityBinding.setPrimaryTableName( superEntityBinding.getPrimaryTableName() );
// Configure discriminator if present
final String discriminatorValue = entitySource.getDiscriminatorMatchValue();
if ( discriminatorValue != null ) {
entityBinding.setDiscriminatorMatchValue( discriminatorValue );
}
else {
entityBinding.setDiscriminatorMatchValue( entitySource.getEntityName() );
}
}
else {
bindPrimaryTable( entityBinding, entitySource );
}
if ( inheritanceType == InheritanceType.JOINED && superEntityBinding != null ) {
ForeignKey fk = entityBinding.getPrimaryTable().createForeignKey(
superEntityBinding.getPrimaryTable(),
( (SubclassEntitySource) entitySource ).getJoinedForeignKeyName()
);
// explicitly maps to target table pk
for ( Column column : entityBinding.getPrimaryTable().getPrimaryKey().getColumns() ) {
fk.addColumn( column );
}
}
// todo: deal with joined and unioned subclass bindings // todo: deal with joined and unioned subclass bindings
// todo: bind fetch profiles // todo: bind fetch profiles
@ -2313,27 +2377,33 @@ public class Binder {
:referencedEntityBinding.locateAttributeBinding( resolutionDelegate.getJoinColumns( resolutionContext ) ); :referencedEntityBinding.locateAttributeBinding( resolutionDelegate.getJoinColumns( resolutionContext ) );
} }
private EntityBinding entityBinding( final String entityName ) { /**
*
* @param entityName
* @return
*/
private EntityBinding findOrBindingEntityBinding(final String entityName) {
// Check if binding has already been created // Check if binding has already been created
EntityBinding entityBinding = metadata.getEntityBinding( entityName ); EntityBinding entityBinding = metadata.getEntityBinding( entityName );
if ( entityBinding == null ) { if ( entityBinding == null ) {
// Find appropriate source to create binding // Find appropriate source to create binding
final EntitySource entitySource = entitySourcesByName.get( entityName ); final EntitySource entitySource = entitySourcesByName.get( entityName );
if(entitySource == null) { if ( entitySource == null ) {
String msg = log.missingEntitySource( entityName ); String msg = log.missingEntitySource( entityName );
bindingContext().makeMappingException( msg ); bindingContext().makeMappingException( msg );
} }
// Get super entity binding (creating it if necessary using recursive call to this method) // Get super entity binding (creating it if necessary using recursive call to this method)
final EntityBinding superEntityBinding = if ( SubclassEntitySource.class.isInstance( entitySource ) ) {
SubclassEntitySource.class.isInstance( entitySource ) String superEntityName = ( (SubclassEntitySource) entitySource ).superclassEntitySource()
? entityBinding( ( ( SubclassEntitySource ) entitySource ).superclassEntitySource().getEntityName() ) .getEntityName();
: null; EntityBinding superEntityBinding = findOrBindingEntityBinding( superEntityName );
// Create entity binding entityBinding = bindSubEntity( entitySource, superEntityBinding );
entityBinding = }
superEntityBinding == null else {
? bindEntities( entityHierarchiesByRootEntitySource.get( entitySource ) ) EntityHierarchy entityHierarchy = entityHierarchiesByRootEntitySource.get( entitySource );
: bindEntity( entitySource, superEntityBinding ); entityBinding = bindEntityHierarchy( entityHierarchy );
}
} }
return entityBinding; return entityBinding;
} }

View File

@ -211,7 +211,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
} }
final HbmMetadataSourceProcessorImpl processor = new HbmMetadataSourceProcessorImpl( this, jaxbRoots ); final HbmMetadataSourceProcessorImpl processor = new HbmMetadataSourceProcessorImpl( this, jaxbRoots );
final Binder binder = new Binder( this, identifierGeneratorFactory ); final Binder binder = new Binder( this, identifierGeneratorFactory );
binder.bindEntities( processor.extractEntityHierarchies() ); binder.bindEntityHierarchies( processor.extractEntityHierarchies() );
} }
@ -350,7 +350,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private void processMappings(MetadataSourceProcessor[] metadataSourceProcessors) { private void processMappings(MetadataSourceProcessor[] metadataSourceProcessors) {
final Binder binder = new Binder( this, identifierGeneratorFactory ); final Binder binder = new Binder( this, identifierGeneratorFactory );
for ( MetadataSourceProcessor processor : metadataSourceProcessors ) { for ( MetadataSourceProcessor processor : metadataSourceProcessors ) {
binder.bindEntities( processor.extractEntityHierarchies() ); binder.bindEntityHierarchies( processor.extractEntityHierarchies() );
} }
} }

View File

@ -473,7 +473,8 @@ public class AssociationAttribute extends MappedAttribute {
if ( joinTableAnnotation != null ) { if ( joinTableAnnotation != null ) {
if ( JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_ONE ) == null if ( JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_ONE ) == null
&& JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_MANY ) == null && JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_MANY ) == null
&& JandexHelper.getSingleAnnotation( annotations, JPADotNames.MANY_TO_MANY ) == null ) { && JandexHelper.getSingleAnnotation( annotations, JPADotNames.MANY_TO_MANY ) == null
&& JandexHelper.getSingleAnnotation( annotations, JPADotNames.MANY_TO_ONE ) == null ) {
String msg = coreLogger.joinTableForNonAssociationAttribute( String msg = coreLogger.joinTableForNonAssociationAttribute(
getContext().getOrigin().getName(), getContext().getOrigin().getName(),
getName() getName()

View File

@ -262,7 +262,7 @@ public class EntityClass extends ConfiguredClass {
return JandexHelper.getValue( jpaEntityAnnotation, "name", String.class ); return JandexHelper.getValue( jpaEntityAnnotation, "name", String.class );
} }
private List<PrimaryKeyJoinColumnSource> determinPrimaryKeyJoinColumns() { protected List<PrimaryKeyJoinColumnSource> determinPrimaryKeyJoinColumns() {
if ( inheritanceType != InheritanceType.JOINED ) { if ( inheritanceType != InheritanceType.JOINED ) {
return null; return null;
} }

View File

@ -32,9 +32,12 @@ import javax.persistence.DiscriminatorType;
import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo; import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName; import org.jboss.jandex.DotName;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingContext; import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute; import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column; import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
@ -43,6 +46,7 @@ import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotName
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames; import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper; import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.spi.binding.InheritanceType;
import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource;
/** /**
* Represents an root entity configured via annotations/orm-xml. * Represents an root entity configured via annotations/orm-xml.
@ -51,6 +55,10 @@ import org.hibernate.metamodel.spi.binding.InheritanceType;
* @author Brett Meyer * @author Brett Meyer
*/ */
public class RootEntityClass extends EntityClass { public class RootEntityClass extends EntityClass {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
RootEntityClass.class.getName()
);
private final IdType idType; private final IdType idType;
private final List<MappedSuperclass> mappedSuperclasses; private final List<MappedSuperclass> mappedSuperclasses;
@ -132,6 +140,14 @@ public class RootEntityClass extends EntityClass {
return isDiscriminatorIncludedInSql; return isDiscriminatorIncludedInSql;
} }
protected List<PrimaryKeyJoinColumnSource> determinPrimaryKeyJoinColumns() {
List<PrimaryKeyJoinColumnSource> results = super.determinPrimaryKeyJoinColumns();
if ( CollectionHelper.isNotEmpty( results ) ) {
LOG.invalidPrimaryKeyJoinColumnAnnotation();
}
return null;
}
@Override @Override
public Collection<BasicAttribute> getSimpleAttributes() { public Collection<BasicAttribute> getSimpleAttributes() {
List<BasicAttribute> attributes = new ArrayList<BasicAttribute>(); List<BasicAttribute> attributes = new ArrayList<BasicAttribute>();

View File

@ -153,9 +153,9 @@ public interface JPADotNames {
DotName GENERATED_VALUE = DotName.createSimple( GeneratedValue.class.getName() ); DotName GENERATED_VALUE = DotName.createSimple( GeneratedValue.class.getName() );
DotName ID = DotName.createSimple( Id.class.getName() ); DotName ID = DotName.createSimple( Id.class.getName() );
DotName ID_CLASS = DotName.createSimple( IdClass.class.getName() ); DotName ID_CLASS = DotName.createSimple( IdClass.class.getName() );
DotName INHERITANCE = DotName.createSimple( Inheritance.class.getName() );
DotName INHERITANCE_TYPE = DotName.createSimple( InheritanceType.class.getName() ); DotName INHERITANCE_TYPE = DotName.createSimple( InheritanceType.class.getName() );
DotName JOIN_COLUMN = DotName.createSimple( JoinColumn.class.getName() ); DotName JOIN_COLUMN = DotName.createSimple( JoinColumn.class.getName() );
DotName INHERITANCE = DotName.createSimple( Inheritance.class.getName() );
DotName JOIN_COLUMNS = DotName.createSimple( JoinColumns.class.getName() ); DotName JOIN_COLUMNS = DotName.createSimple( JoinColumns.class.getName() );
DotName JOIN_TABLE = DotName.createSimple( JoinTable.class.getName() ); DotName JOIN_TABLE = DotName.createSimple( JoinTable.class.getName() );
DotName LOB = DotName.createSimple( Lob.class.getName() ); DotName LOB = DotName.createSimple( Lob.class.getName() );

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -35,6 +36,9 @@ import org.hibernate.EntityMode;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.internal.util.ValueHolder; import org.hibernate.internal.util.ValueHolder;
import org.hibernate.internal.util.collections.JoinedIterable; import org.hibernate.internal.util.collections.JoinedIterable;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.internal.util.collections.SingletonIterator;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.spi.domain.AttributeContainer; import org.hibernate.metamodel.spi.domain.AttributeContainer;
import org.hibernate.metamodel.spi.domain.Entity; import org.hibernate.metamodel.spi.domain.Entity;
import org.hibernate.metamodel.spi.domain.SingularAttribute; import org.hibernate.metamodel.spi.domain.SingularAttribute;
@ -102,7 +106,8 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
private Map<String, AttributeBinding> attributeBindingMap = new HashMap<String, AttributeBinding>(); private Map<String, AttributeBinding> attributeBindingMap = new HashMap<String, AttributeBinding>();
private List<JpaCallbackSource> jpaCallbackClasses = new ArrayList<JpaCallbackSource>(); private List<JpaCallbackSource> jpaCallbackClasses = new ArrayList<JpaCallbackSource>();
private final int subEntityBindingId;
private int nextSubEntityBindingId = 0;
/** /**
* Used to instantiate the EntityBinding for an entity that is the root of an inheritance hierarchy * Used to instantiate the EntityBinding for an entity that is the root of an inheritance hierarchy
* *
@ -112,6 +117,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
public EntityBinding(InheritanceType inheritanceType, EntityMode entityMode) { public EntityBinding(InheritanceType inheritanceType, EntityMode entityMode) {
this.superEntityBinding = null; this.superEntityBinding = null;
this.hierarchyDetails = new HierarchyDetails( this, inheritanceType, entityMode ); this.hierarchyDetails = new HierarchyDetails( this, inheritanceType, entityMode );
this.subEntityBindingId = 0;
} }
/** /**
@ -123,6 +129,11 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
this.superEntityBinding = superEntityBinding; this.superEntityBinding = superEntityBinding;
this.superEntityBinding.subEntityBindings.add( this ); this.superEntityBinding.subEntityBindings.add( this );
this.hierarchyDetails = superEntityBinding.getHierarchyDetails(); this.hierarchyDetails = superEntityBinding.getHierarchyDetails();
this.subEntityBindingId = superEntityBinding.nextSubEntityBindingId();
}
private int nextSubEntityBindingId(){
return ++nextSubEntityBindingId;
} }
public HierarchyDetails getHierarchyDetails() { public HierarchyDetails getHierarchyDetails() {
@ -133,6 +144,10 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
return superEntityBinding; return superEntityBinding;
} }
public int getSubEntityBindingId() {
return subEntityBindingId;
}
public boolean isRoot() { public boolean isRoot() {
return superEntityBinding == null; return superEntityBinding == null;
} }
@ -578,6 +593,21 @@ public class EntityBinding extends AbstractAttributeBindingContainer {
return new JoinedIterable<AttributeBinding>( iterables ); return new JoinedIterable<AttributeBinding>( iterables );
} }
public Iterator<TableSpecification> getTableClosureIterator() {
if ( superEntityBinding == null ) {
return new SingletonIterator<TableSpecification>( getPrimaryTable() );
}
else {
return new JoinedIterator<TableSpecification>(
superEntityBinding.getTableClosureIterator(),
new SingletonIterator<TableSpecification>( getPrimaryTable() )
);
}
}
public Iterator getKeyClosureIterator(){
return null;
}
public void setJpaCallbackClasses(List<JpaCallbackSource> jpaCallbackClasses) { public void setJpaCallbackClasses(List<JpaCallbackSource> jpaCallbackClasses) {
this.jpaCallbackClasses = jpaCallbackClasses; this.jpaCallbackClasses = jpaCallbackClasses;
} }

View File

@ -25,7 +25,9 @@ package org.hibernate.metamodel.spi.relational;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.sql.Template;
/** /**
* Models a physical column * Models a physical column
@ -128,6 +130,25 @@ public class Column extends AbstractValue {
this.comment = comment; this.comment = comment;
} }
public String getTemplate(Dialect dialect, SQLFunctionRegistry functionRegistry) {
return hasCustomRead()
? Template.renderWhereStringTemplate( readFragment, dialect, functionRegistry )
: Template.TEMPLATE + '.' + getColumnName().getText( dialect );
}
public boolean hasCustomRead() {
return StringHelper.isNotEmpty( readFragment );
}
public String getReadExpr(Dialect dialect) {
return hasCustomRead() ? readFragment : getColumnName().getText( dialect );
}
public String getWriteExpr() {
return StringHelper.isNotEmpty( writeFragment ) ? writeFragment : "?";
}
public Size getSize() { public Size getSize() {
return size; return size;
} }

View File

@ -2140,7 +2140,7 @@ public abstract class AbstractCollectionPersister
} }
} }
@Override
public int getSize(Serializable key, SessionImplementor session) { public int getSize(Serializable key, SessionImplementor session) {
try { try {
PreparedStatement st = session.getTransactionCoordinator() PreparedStatement st = session.getTransactionCoordinator()

View File

@ -186,16 +186,16 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
return delete.toStatementString(); return delete.toStatementString();
} }
@Override
public boolean consumesEntityAlias() { public boolean consumesEntityAlias() {
return false; return false;
} }
@Override
public boolean consumesCollectionAlias() { public boolean consumesCollectionAlias() {
// return !isOneToMany(); // return !isOneToMany();
return true; return true;
} }
@Override
public boolean isOneToMany() { public boolean isOneToMany() {
return false; return false;
} }
@ -210,8 +210,10 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
@Override @Override
protected int doUpdateRows(Serializable id, PersistentCollection collection, SessionImplementor session) protected int doUpdateRows(Serializable id, PersistentCollection collection, SessionImplementor session)
throws HibernateException { throws HibernateException {
if ( ArrayHelper.isAllFalse(elementColumnIsSettable) ) return 0; if ( ArrayHelper.isAllFalse( elementColumnIsSettable ) ) {
return 0;
}
try { try {
PreparedStatement st = null; PreparedStatement st = null;
@ -342,11 +344,11 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
throws MappingException { throws MappingException {
return BatchingCollectionInitializer.createBatchingCollectionInitializer( this, batchSize, getFactory(), loadQueryInfluencers ); return BatchingCollectionInitializer.createBatchingCollectionInitializer( this, batchSize, getFactory(), loadQueryInfluencers );
} }
@Override
public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) { public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
return ""; return "";
} }
@Override
public String whereJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) { public String whereJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
return ""; return "";
} }

View File

@ -507,8 +507,8 @@ public abstract class AbstractEntityPersister
this.naturalIdRegionAccessStrategy = naturalIdRegionAccessStrategy; this.naturalIdRegionAccessStrategy = naturalIdRegionAccessStrategy;
isLazyPropertiesCacheable = persistentClass.isLazyPropertiesCacheable(); isLazyPropertiesCacheable = persistentClass.isLazyPropertiesCacheable();
this.cacheEntryStructure = factory.getSettings().isStructuredCacheEntriesEnabled() ? this.cacheEntryStructure = factory.getSettings().isStructuredCacheEntriesEnabled() ?
(CacheEntryStructure) new StructuredCacheEntry(this) : new StructuredCacheEntry(this) :
(CacheEntryStructure) new UnstructuredCacheEntry(); new UnstructuredCacheEntry();
this.entityMetamodel = new EntityMetamodel( persistentClass, factory ); this.entityMetamodel = new EntityMetamodel( persistentClass, factory );
this.entityTuplizer = this.entityMetamodel.getTuplizer(); this.entityTuplizer = this.entityMetamodel.getTuplizer();

View File

@ -53,6 +53,8 @@ import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.EntityDiscriminator; import org.hibernate.metamodel.spi.binding.EntityDiscriminator;
import org.hibernate.metamodel.spi.relational.DerivedValue; import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.PrimaryKey;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.sql.CaseFragment; import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.SelectFragment; import org.hibernate.sql.SelectFragment;
import org.hibernate.type.*; import org.hibernate.type.*;
@ -517,20 +519,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
super( entityBinding, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory ); super( entityBinding, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory );
// DISCRIMINATOR // DISCRIMINATOR
if ( entityBinding.isPolymorphic() ) { if ( entityBinding.isPolymorphic() ) {
EntityDiscriminator discriminator = entityBinding.getHierarchyDetails().getEntityDiscriminator(); try{
discriminator.getRelationalValue(); discriminatorValue = entityBinding.getSubEntityBindingId();
Type discriminatorType = discriminator discriminatorSQLString = discriminatorValue.toString();
.getExplicitHibernateTypeDescriptor() } catch ( Exception e ){
.getResolvedTypeMapping();
try {
org.hibernate.type.DiscriminatorType dtype = (org.hibernate.type.DiscriminatorType) discriminatorType;
discriminatorValue = dtype.stringToObject( entityBinding.getDiscriminatorMatchValue() );
discriminatorSQLString = dtype.objectToSQLString( discriminatorValue, factory.getDialect() );
}
catch ( ClassCastException cce ) {
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
}
catch ( Exception e ) {
throw new MappingException( "Could not format discriminator value to SQL string", e ); throw new MappingException( "Could not format discriminator value to SQL string", e );
} }
} }
@ -546,27 +538,54 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final int idColumnSpan = getIdentifierColumnSpan(); final int idColumnSpan = getIdentifierColumnSpan();
ArrayList tables = new ArrayList(); ArrayList<String> tables = new ArrayList<String>();
ArrayList keyColumns = new ArrayList(); ArrayList keyColumns = new ArrayList();
ArrayList keyColumnReaders = new ArrayList(); ArrayList keyColumnReaders = new ArrayList();
ArrayList keyColumnReaderTemplates = new ArrayList(); ArrayList keyColumnReaderTemplates = new ArrayList();
ArrayList cascadeDeletes = new ArrayList(); ArrayList cascadeDeletes = new ArrayList();
// Iterator titer = persistentClass.getTableClosureIterator(); Iterator<TableSpecification> titer = entityBinding.getTableClosureIterator();
// Iterator kiter = persistentClass.getKeyClosureIterator(); while ( titer.hasNext() ){
TableSpecification table = titer.next();
String tableName = table.getLogicalName().getText(factory.getDialect());
tables.add( tableName );
String[] keyCols = new String[idColumnSpan];
String[] keyColReaders = new String[idColumnSpan];
String[] keyColReaderTemplates = new String[idColumnSpan];
PrimaryKey primaryKey= table.getPrimaryKey();
for ( int k = 0; k < idColumnSpan; k++ ) {
org.hibernate.metamodel.spi.relational.Column column = primaryKey.getColumns().get( k );
keyCols[k] = column.getColumnName().getText(factory.getDialect());
keyColReaders[k] = column.getReadExpr( factory.getDialect() );
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
}
keyColumns.add( keyCols );
keyColumnReaders.add( keyColReaders );
keyColumnReaderTemplates.add( keyColReaderTemplates );
cascadeDeletes.add( false && factory.getDialect().supportsCascadeDelete() ); //todo add @OnDelete support
}
//Span of the tables directly mapped by this entity and super-classes, if any
coreTableSpan = tables.size();
//todo secondary table
isNullableTable = new boolean[]{true};
naturalOrderTableNames = ArrayHelper.toStringArray( tables );
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray( keyColumns );
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray( keyColumnReaders );
naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray( keyColumnReaderTemplates );
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray( cascadeDeletes );
ArrayList subtables = new ArrayList();
ArrayList isConcretes = new ArrayList();
ArrayList isDeferreds = new ArrayList();
ArrayList isLazies = new ArrayList();
keyColumns = new ArrayList();
//todo add sub class tables here
//---------------------------------------------- //----------------------------------------------
tableSpan = -1; tableSpan = -1;
tableNames = null; tableNames = null;
naturalOrderTableNames = null;
tableKeyColumns = null; tableKeyColumns = null;
tableKeyColumnReaders = null; tableKeyColumnReaders = null;
tableKeyColumnReaderTemplates = null; tableKeyColumnReaderTemplates = null;
naturalOrderTableKeyColumns = null;
naturalOrderTableKeyColumnReaders = null;
naturalOrderTableKeyColumnReaderTemplates = null;
naturalOrderCascadeDeleteEnabled = null;
spaces = null; spaces = null;
subclassClosure = null; subclassClosure = null;
subclassTableNameClosure = null; subclassTableNameClosure = null;
@ -584,8 +603,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
notNullColumnTableNumbers = null; notNullColumnTableNumbers = null;
constraintOrderedTableNames = null; constraintOrderedTableNames = null;
constraintOrderedKeyColumnNames = null; constraintOrderedKeyColumnNames = null;
coreTableSpan = -1;
isNullableTable = null;
//----------------------------- //-----------------------------
initLockers(); initLockers();
initSubclassPropertyAliasesMap( entityBinding ); initSubclassPropertyAliasesMap( entityBinding );

View File

@ -75,7 +75,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
private final String[] subclassSpaces; private final String[] subclassSpaces;
private final Object discriminatorValue; private final Object discriminatorValue;
private final String discriminatorSQLValue; private final String discriminatorSQLValue;
private final Map subclassByDiscriminatorValue = new HashMap(); private final Map<Integer,String> subclassByDiscriminatorValue = new HashMap<Integer,String>();
private final String[] constraintOrderedTableNames; private final String[] constraintOrderedTableNames;
private final String[][] constraintOrderedKeyColumnNames; private final String[][] constraintOrderedKeyColumnNames;
@ -185,7 +185,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
spaces[i] = (String) iter.next(); spaces[i] = (String) iter.next();
} }
HashSet subclassTables = new HashSet(); HashSet<String> subclassTables = new HashSet<String>();
iter = persistentClass.getSubclassTableClosureIterator(); iter = persistentClass.getSubclassTableClosureIterator();
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
Table table = (Table) iter.next(); Table table = (Table) iter.next();
@ -251,7 +251,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
super(entityBinding, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory ); super(entityBinding, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory );
// TODO: implement!!! initializing final fields to null to make compiler happy. // TODO: implement!!! initializing final fields to null to make compiler happy.
subquery = null; subquery = null;
tableName = null; tableName = entityBinding.getPrimaryTable().getQualifiedName( factory.getDialect() );
subclassClosure = null; subclassClosure = null;
spaces = null; spaces = null;
subclassSpaces = null; subclassSpaces = null;