Implementation of the "table-per-concrete-class" or "roll-down" mapping
strategy for an entity and its inheritence hierarchy.
| Constructor: |
public UnionSubclassEntityPersister(PersistentClass persistentClass,
EntityRegionAccessStrategy cacheAccessStrategy,
SessionFactoryImplementor factory,
Mapping mapping) throws HibernateException {
//INITIALIZATION:
super( persistentClass, cacheAccessStrategy, factory );
if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
throw new MappingException(
"Cannot use identity column key generation with < union-subclass > mapping for: " +
getEntityName()
);
}
// TABLE
tableName = persistentClass.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
/*rootTableName = persistentClass.getRootTable().getQualifiedName(
factory.getDialect(),
factory.getDefaultCatalog(),
factory.getDefaultSchema()
);*/
//Custom SQL
String sql;
boolean callable = false;
ExecuteUpdateResultCheckStyle checkStyle = null;
sql = persistentClass.getCustomSQLInsert();
callable = sql != null && persistentClass.isCustomInsertCallable();
checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: persistentClass.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: persistentClass.getCustomSQLInsertCheckStyle();
customSQLInsert = new String[] { sql };
insertCallable = new boolean[] { callable };
insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
sql = persistentClass.getCustomSQLUpdate();
callable = sql != null && persistentClass.isCustomUpdateCallable();
checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: persistentClass.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: persistentClass.getCustomSQLUpdateCheckStyle();
customSQLUpdate = new String[] { sql };
updateCallable = new boolean[] { callable };
updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
sql = persistentClass.getCustomSQLDelete();
callable = sql != null && persistentClass.isCustomDeleteCallable();
checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: persistentClass.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: persistentClass.getCustomSQLDeleteCheckStyle();
customSQLDelete = new String[] { sql };
deleteCallable = new boolean[] { callable };
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
discriminatorSQLValue = String.valueOf( persistentClass.getSubclassId() );
// PROPERTIES
int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName();
// SUBCLASSES
subclassByDiscriminatorValue.put(
new Integer( persistentClass.getSubclassId() ),
persistentClass.getEntityName()
);
if ( persistentClass.isPolymorphic() ) {
Iterator iter = persistentClass.getSubclassIterator();
int k=1;
while ( iter.hasNext() ) {
Subclass sc = (Subclass) iter.next();
subclassClosure[k++] = sc.getEntityName();
subclassByDiscriminatorValue.put( new Integer( sc.getSubclassId() ), sc.getEntityName() );
}
}
//SPACES
//TODO: i'm not sure, but perhaps we should exclude
// abstract denormalized tables?
int spacesSize = 1 + persistentClass.getSynchronizedTables().size();
spaces = new String[spacesSize];
spaces[0] = tableName;
Iterator iter = persistentClass.getSynchronizedTables().iterator();
for ( int i=1; i< spacesSize; i++ ) {
spaces[i] = (String) iter.next();
}
HashSet subclassTables = new HashSet();
iter = persistentClass.getSubclassTableClosureIterator();
while ( iter.hasNext() ) {
Table table = (Table) iter.next();
subclassTables.add( table.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
) );
}
subclassSpaces = ArrayHelper.toStringArray(subclassTables);
subquery = generateSubquery(persistentClass, mapping);
if ( isMultiTable() ) {
int idColumnSpan = getIdentifierColumnSpan();
ArrayList tableNames = new ArrayList();
ArrayList keyColumns = new ArrayList();
if ( !isAbstract() ) {
tableNames.add( tableName );
keyColumns.add( getIdentifierColumnNames() );
}
iter = persistentClass.getSubclassTableClosureIterator();
while ( iter.hasNext() ) {
Table tab = ( Table ) iter.next();
if ( !tab.isAbstractUnionTable() ) {
String tableName = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
tableNames.add( tableName );
String[] key = new String[idColumnSpan];
Iterator citer = tab.getPrimaryKey().getColumnIterator();
for ( int k=0; k< idColumnSpan; k++ ) {
key[k] = ( ( Column ) citer.next() ).getQuotedName( factory.getDialect() );
}
keyColumns.add( key );
}
}
constraintOrderedTableNames = ArrayHelper.toStringArray( tableNames );
constraintOrderedKeyColumnNames = ArrayHelper.to2DStringArray( keyColumns );
}
else {
constraintOrderedTableNames = new String[] { tableName };
constraintOrderedKeyColumnNames = new String[][] { getIdentifierColumnNames() };
}
initLockers();
initSubclassPropertyAliasesMap(persistentClass);
postConstruct(mapping);
}
|
| Methods from org.hibernate.persister.entity.AbstractEntityPersister: |
|---|
|
addDiscriminatorToInsert, addDiscriminatorToSelect, afterInitialize, afterReassociate, canExtractIdOutOfEntity, check, concretePropertySelectFragment, concretePropertySelectFragment, concretePropertySelectFragment, concretePropertySelectFragmentSansLeadingComma, consumesCollectionAlias, consumesEntityAlias, countSubclassProperties, createEntityLoader, createEntityLoader, createFrom, createJoin, createJoin, createProxy, createQueryLoader, createSelect, createUniqueKeyLoaders, createWhereByKey, dehydrate, dehydrate, delete, delete, filterFragment, filterFragment, findDirty, findModified, forceVersionIncrement, fromJoinFragment, generateDeleteString, generateFilterConditionAlias, generateIdentityInsertString, generateInsertGeneratedValuesSelectString, generateInsertString, generateInsertString, generateInsertString, generateLazySelectString, generateLocker, generateSelectVersionString, generateSnapshotSelectString, generateTableAlias, generateUpdateGeneratedValuesSelectString, generateUpdateString, generateUpdateString, getCacheAccessStrategy, getCacheEntryStructure, getCascadeStyle, getClassMetadata, getConcreteProxyClass, getCurrentVersion, getDatabaseSnapshot, getDiscriminatorAlias, getDiscriminatorAlias, getDiscriminatorColumnName, getDiscriminatorFormulaTemplate, getEntityMetamodel, getEntityName, getEntityType, getFactory, getFetchMode, getIdentifier, getIdentifierAliases, getIdentifierAliases, getIdentifierColumnNames, getIdentifierColumnSpan, getIdentifierGenerator, getIdentifierPropertyName, getIdentifierType, getIdentitySelectString, getKeyColumnNames, getKeyColumns, getLazyProperties, getMappedClass, getMappedSuperclass, getName, getNaturalIdentifierProperties, getNaturalIdentifierSnapshot, getNonLazyPropertyUpdateability, getPropertiesToInsert, getPropertiesToUpdate, getPropertyAliases, getPropertyCascadeStyles, getPropertyCheckability, getPropertyColumnNames, getPropertyColumnNames, getPropertyColumnSpan, getPropertyIndex, getPropertyInsertGenerationInclusions, getPropertyInsertability, getPropertyLaziness, getPropertyNames, getPropertyNullability, getPropertySpan, getPropertySubclassNames, getPropertyTableNumbers, getPropertyTableNumbersInSelect, getPropertyType, getPropertyTypes, getPropertyUpdateGenerationInclusions, getPropertyUpdateability, getPropertyUpdateability, getPropertyValue, getPropertyValue, getPropertyValues, getPropertyValuesToInsert, getPropertyVersionability, getQuerySpaces, getRootEntityName, getRootTableAlias, getRootTableIdentifierColumnNames, getRootTableKeyColumnNames, getRootTableName, getSQLDeleteStrings, getSQLIdentityInsertString, getSQLInsertStrings, getSQLLazySelectString, getSQLLazyUpdateByRowIdStrings, getSQLLazyUpdateStrings, getSQLSnapshotSelectString, getSQLUpdateByRowIdStrings, getSQLUpdateStrings, getSQLWhereString, getSelectByUniqueKeyString, getSequentialSelect, getSubclassColumnAliasClosure, getSubclassColumnClosure, getSubclassColumnLazyiness, getSubclassColumnTableNumberClosure, getSubclassEntityPersister, getSubclassFormulaAliasClosure, getSubclassFormulaClosure, getSubclassFormulaLazyiness, getSubclassFormulaTableNumberClosure, getSubclassFormulaTemplateClosure, getSubclassPropertyColumnAliases, getSubclassPropertyColumnNameClosure, getSubclassPropertyColumnNames, getSubclassPropertyColumnNames, getSubclassPropertyDeclarer, getSubclassPropertyFormulaTemplateClosure, getSubclassPropertyName, getSubclassPropertyNameClosure, getSubclassPropertySubclassNameClosure, getSubclassPropertyTableNumber, getSubclassPropertyTableNumber, getSubclassPropertyType, getSubclassPropertyTypeClosure, getSubclassTableKeyColumns, getSubclassTableName, getSubclassTableSpan, getTableName, getTableSpan, getTableUpdateNeeded, getTemporaryIdTableDDL, getTemporaryIdTableName, getTuplizer, getTuplizer, getType, getVersion, getVersionColumnName, getVersionComparator, getVersionProperty, getVersionSelectString, getVersionType, getVersionedTableName, guessEntityMode, hasCache, hasCascades, hasCollections, hasEmbeddedCompositeIdentifier, hasFormulaProperties, hasIdentifierProperty, hasInsertGeneratedProperties, hasLazyProperties, hasMutableProperties, hasNaturalIdentifier, hasProxy, hasRowId, hasSequentialSelect, hasSubclasses, hasSubselectLoadableCollections, hasUninitializedLazyProperties, hasUpdateGeneratedProperties, hasWhere, hydrate, identifierSelectFragment, implementsLifecycle, implementsValidatable, initLockers, initPropertyPaths, initSubclassPropertyAliasesMap, initializeLazyProperty, insert, insert, insert, insert, instantiate, isAbstract, isBatchLoadable, isBatchable, isCacheInvalidationRequired, isClassOrSuperclassTable, isCollection, isDefinedOnSubclass, isDeleteCallable, isExplicitPolymorphism, isIdentifierAssignedByInsert, isInherited, isInsertCallable, isInstance, isInstrumented, isInverseSubclassTable, isInverseTable, isLazyPropertiesCacheable, isMultiTable, isMutable, isNullableSubclassTable, isNullableTable, isPolymorphic, isPropertyOfTable, isSelectBeforeUpdateRequired, isSubclassEntityName, isSubclassPropertyDeferred, isSubclassPropertyNullable, isSubclassTableLazy, isSubclassTableSequentialSelect, isTableCascadeDeleteEnabled, isTransient, isUpdateCallable, isVersionPropertyGenerated, isVersionPropertyInsertable, isVersioned, load, loadByUniqueKey, lock, logStaticSQL, oneToManyFilterFragment, optimisticLockMode, postConstruct, postInstantiate, processInsertGeneratedProperties, processUpdateGeneratedProperties, propertySelectFragment, renderSelect, resetIdentifier, selectFragment, selectFragment, setIdentifier, setPropertyValue, setPropertyValue, setPropertyValues, toColumns, toColumns, toColumns, toString, toType, update, update, updateOrInsert, useDynamicInsert, useDynamicUpdate, useGetGeneratedKeys, useInsertSelectIdentity, whereJoinFragment |
| Method from org.hibernate.persister.entity.UnionSubclassEntityPersister Detail: |
protected void addDiscriminatorToSelect(SelectFragment select,
String name,
String suffix) {
select.addColumn( name, getDiscriminatorColumnName(), getDiscriminatorAlias() );
}
|
public String filterFragment(String name) {
return hasWhere() ?
" and " + getSQLWhereString(name) :
"";
}
|
public String fromTableFragment(String name) {
return getTableName() + ' " + name;
}
|
protected String generateSelectString(LockMode lockMode) {
SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
.setLockMode(lockMode)
.setTableName( getTableName() )
.addColumns( getIdentifierColumnNames() )
.addColumns(
getSubclassColumnClosure(),
getSubclassColumnAliasClosure(),
getSubclassColumnLazyiness()
)
.addColumns(
getSubclassFormulaClosure(),
getSubclassFormulaAliasClosure(),
getSubclassFormulaLazyiness()
);
//TODO: include the rowids!!!!
if ( hasSubclasses() ) {
if ( isDiscriminatorFormula() ) {
select.addColumn( getDiscriminatorFormula(), getDiscriminatorAlias() );
}
else {
select.addColumn( getDiscriminatorColumnName(), getDiscriminatorAlias() );
}
}
if ( getFactory().getSettings().isCommentsEnabled() ) {
select.setComment( "load " + getEntityName() );
}
return select.addCondition( getIdentifierColumnNames(), "=?" ).toStatementString();
}
Generate the SQL that selects a row by id |
protected String generateSubquery(PersistentClass model,
Mapping mapping) {
Dialect dialect = getFactory().getDialect();
Settings settings = getFactory().getSettings();
if ( !model.hasSubclasses() ) {
return model.getTable().getQualifiedName(
dialect,
settings.getDefaultCatalogName(),
settings.getDefaultSchemaName()
);
}
HashSet columns = new HashSet();
Iterator titer = model.getSubclassTableClosureIterator();
while ( titer.hasNext() ) {
Table table = (Table) titer.next();
if ( !table.isAbstractUnionTable() ) {
Iterator citer = table.getColumnIterator();
while ( citer.hasNext() ) columns.add( citer.next() );
}
}
StringBuffer buf = new StringBuffer()
.append("( ");
Iterator siter = new JoinedIterator(
new SingletonIterator(model),
model.getSubclassIterator()
);
while ( siter.hasNext() ) {
PersistentClass clazz = (PersistentClass) siter.next();
Table table = clazz.getTable();
if ( !table.isAbstractUnionTable() ) {
//TODO: move to .sql package!!
buf.append("select ");
Iterator citer = columns.iterator();
while ( citer.hasNext() ) {
Column col = (Column) citer.next();
if ( !table.containsColumn(col) ) {
int sqlType = col.getSqlTypeCode(mapping);
buf.append( dialect.getSelectClauseNullString(sqlType) )
.append(" as ");
}
buf.append( col.getName() );
buf.append(", ");
}
buf.append( clazz.getSubclassId() )
.append(" as clazz_");
buf.append(" from ")
.append( table.getQualifiedName(
dialect,
settings.getDefaultCatalogName(),
settings.getDefaultSchemaName()
) );
buf.append(" union ");
if ( dialect.supportsUnionAll() ) {
buf.append("all ");
}
}
}
if ( buf.length() > 2 ) {
//chop the last union (all)
buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) );
}
return buf.append(" )").toString();
}
|
public String[] getConstraintOrderedTableNameClosure() {
return constraintOrderedTableNames;
}
|
public String[][] getContraintOrderedTableKeyColumnClosure() {
return constraintOrderedKeyColumnNames;
}
|
protected String getDiscriminatorFormula() {
return null;
}
|
public String getDiscriminatorSQLValue() {
return discriminatorSQLValue;
}
|
public Type getDiscriminatorType() {
return Hibernate.INTEGER;
}
|
protected String[] getKeyColumns(int j) {
return getIdentifierColumnNames();
}
|
public Serializable[] getPropertySpaces() {
return spaces;
}
|
public String getPropertyTableName(String propertyName) {
//TODO: check this....
return getTableName();
}
|
protected int[] getPropertyTableNumbers() {
return new int[ getPropertySpan() ];
}
|
protected int[] getPropertyTableNumbersInSelect() {
return new int[ getPropertySpan() ];
}
|
public Serializable[] getQuerySpaces() {
return subclassSpaces;
}
|
public String[] getSubclassClosure() {
return subclassClosure;
}
|
protected int[] getSubclassColumnTableNumberClosure() {
return new int[ getSubclassColumnClosure().length ];
}
|
public String getSubclassForDiscriminatorValue(Object value) {
return (String) subclassByDiscriminatorValue.get(value);
}
|
protected int[] getSubclassFormulaTableNumberClosure() {
return new int[ getSubclassFormulaClosure().length ];
}
|
public String getSubclassPropertyTableName(int i) {
return getTableName();//ie. the subquery! yuck!
}
|
protected int getSubclassPropertyTableNumber(int i) {
return 0;
}
|
public int getSubclassPropertyTableNumber(String propertyName) {
return 0;
}
|
protected String[] getSubclassTableKeyColumns(int j) {
if (j!=0) throw new AssertionFailure("only one table");
return getIdentifierColumnNames();
}
|
public String getSubclassTableName(int j) {
if (j!=0) throw new AssertionFailure("only one table");
return tableName;
}
|
public int getSubclassTableSpan() {
return 1;
}
|
protected boolean[] getTableHasColumns() {
return new boolean[] { true };
}
|
public String getTableName() {
return subquery;
}
|
protected String getTableName(int j) {
return tableName;
}
|
public int getTableSpan() {
return 1;
}
|
protected boolean isClassOrSuperclassTable(int j) {
if (j!=0) throw new AssertionFailure("only one table");
return true;
}
|
protected boolean isDiscriminatorFormula() {
return false;
}
|
public boolean isMultiTable() {
// This could also just be true all the time...
return isAbstract() || hasSubclasses();
}
|
protected boolean isPropertyOfTable(int property,
int j) {
return true;
}
|
protected boolean isTableCascadeDeleteEnabled(int j) {
return false;
}
|