Constructors Summary |
---|
public JoinedSubclassEntityPersister(org.hibernate.mapping.PersistentClass persistentClass, org.hibernate.cache.CacheConcurrencyStrategy cache, org.hibernate.engine.SessionFactoryImplementor factory, org.hibernate.engine.Mapping mapping)
//INITIALIZATION:
super(persistentClass, cache, factory);
// DISCRIMINATOR
final Object discriminatorValue;
if ( persistentClass.isPolymorphic() ) {
try {
discriminatorValue = new Integer( persistentClass.getSubclassId() );
discriminatorSQLString = discriminatorValue.toString();
}
catch (Exception e) {
throw new MappingException("Could not format discriminator value to SQL string", e );
}
}
else {
discriminatorValue = null;
discriminatorSQLString = null;
}
if ( optimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION ) {
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
}
//MULTITABLES
final int idColumnSpan = getIdentifierColumnSpan();
ArrayList tables = new ArrayList();
ArrayList keyColumns = new ArrayList();
ArrayList cascadeDeletes = new ArrayList();
Iterator titer = persistentClass.getTableClosureIterator();
Iterator kiter = persistentClass.getKeyClosureIterator();
while ( titer.hasNext() ) {
Table tab = (Table) titer.next();
KeyValue key = (KeyValue) kiter.next();
String tabname = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
tables.add(tabname);
String[] keyCols = new String[idColumnSpan];
Iterator citer = key.getColumnIterator();
for ( int k=0; k<idColumnSpan; k++ ) {
keyCols[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
}
keyColumns.add(keyCols);
cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
}
naturalOrderTableNames = ArrayHelper.toStringArray(tables);
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
ArrayList subtables = new ArrayList();
ArrayList isConcretes = new ArrayList();
keyColumns = new ArrayList();
titer = persistentClass.getSubclassTableClosureIterator();
while ( titer.hasNext() ) {
Table tab = (Table) titer.next();
isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
String tabname = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
subtables.add(tabname);
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);
}
subclassTableNameClosure = ArrayHelper.toStringArray(subtables);
subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
constraintOrderedTableNames = new String[subclassTableNameClosure.length];
constraintOrderedKeyColumnNames = new String[subclassTableNameClosure.length][];
int currentPosition = 0;
for ( int i = subclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
constraintOrderedTableNames[currentPosition] = subclassTableNameClosure[i];
constraintOrderedKeyColumnNames[currentPosition] = subclassTableKeyColumnClosure[i];
}
tableSpan = naturalOrderTableNames.length;
tableNames = reverse(naturalOrderTableNames);
tableKeyColumns = reverse(naturalOrderTableKeyColumns);
reverse(subclassTableNameClosure, tableSpan);
reverse(subclassTableKeyColumnClosure, tableSpan);
spaces = ArrayHelper.join(
tableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
);
// Custom sql
customSQLInsert = new String[tableSpan];
customSQLUpdate = new String[tableSpan];
customSQLDelete = new String[tableSpan];
insertCallable = new boolean[tableSpan];
updateCallable = new boolean[tableSpan];
deleteCallable = new boolean[tableSpan];
insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
PersistentClass pc = persistentClass;
int jk = tableSpan-1;
while (pc!=null) {
customSQLInsert[jk] = pc.getCustomSQLInsert();
insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
: pc.getCustomSQLInsertCheckStyle();
customSQLUpdate[jk] = pc.getCustomSQLUpdate();
updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
: pc.getCustomSQLUpdateCheckStyle();
customSQLDelete[jk] = pc.getCustomSQLDelete();
deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
: pc.getCustomSQLDeleteCheckStyle();
jk--;
pc = pc.getSuperclass();
}
if ( jk != -1 ) {
throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
}
// PROPERTIES
int hydrateSpan = getPropertySpan();
naturalOrderPropertyTableNumbers = new int[hydrateSpan];
propertyTableNumbers = new int[hydrateSpan];
Iterator iter = persistentClass.getPropertyClosureIterator();
int i=0;
while( iter.hasNext() ) {
Property prop = (Property) iter.next();
String tabname = prop.getValue().getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
propertyTableNumbers[i] = getTableId(tabname, tableNames);
naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames);
i++;
}
// subclass closure properties
//TODO: code duplication with SingleTableEntityPersister
ArrayList columnTableNumbers = new ArrayList();
ArrayList formulaTableNumbers = new ArrayList();
ArrayList propTableNumbers = new ArrayList();
iter = persistentClass.getSubclassPropertyClosureIterator();
while ( iter.hasNext() ) {
Property prop = (Property) iter.next();
Table tab = prop.getValue().getTable();
String tabname = tab.getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
propTableNumbers.add(tabnum);
Iterator citer = prop.getColumnIterator();
while ( citer.hasNext() ) {
Selectable thing = (Selectable) citer.next();
if ( thing.isFormula() ) {
formulaTableNumbers.add(tabnum);
}
else {
columnTableNumbers.add(tabnum);
}
}
}
subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers);
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers);
subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers);
// SUBCLASSES
int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan];
subclassClosure[subclassSpan-1] = getEntityName();
if ( persistentClass.isPolymorphic() ) {
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
discriminatorValues = new String[subclassSpan];
discriminatorValues[subclassSpan-1] = discriminatorSQLString;
notNullColumnTableNumbers = new int[subclassSpan];
final int id = getTableId(
persistentClass.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
),
subclassTableNameClosure
);
notNullColumnTableNumbers[subclassSpan-1] = id;
notNullColumnNames = new String[subclassSpan];
notNullColumnNames[subclassSpan-1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
}
else {
discriminatorValues = null;
notNullColumnTableNumbers = null;
notNullColumnNames = null;
}
iter = persistentClass.getSubclassIterator();
int k=0;
while ( iter.hasNext() ) {
Subclass sc = (Subclass) iter.next();
subclassClosure[k] = sc.getEntityName();
try {
if ( persistentClass.isPolymorphic() ) {
// we now use subclass ids that are consistent across all
// persisters for a class hierarchy, so that the use of
// "foo.class = Bar" works in HQL
Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
discriminatorValues[k] = subclassId.toString();
int id = getTableId(
sc.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
),
subclassTableNameClosure
);
notNullColumnTableNumbers[k] = id;
notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
}
}
catch (Exception e) {
throw new MappingException("Error parsing discriminator value", e );
}
k++;
}
initLockers();
initSubclassPropertyAliasesMap(persistentClass);
postConstruct(mapping);
|
Methods Summary |
---|
public void | addDiscriminatorToSelect(org.hibernate.sql.SelectFragment select, java.lang.String name, java.lang.String suffix)
if ( hasSubclasses() ) {
select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() );
}
|
private org.hibernate.sql.CaseFragment | discriminatorFragment(java.lang.String alias)
CaseFragment cases = getFactory().getDialect().createCaseFragment();
for ( int i=0; i<discriminatorValues.length; i++ ) {
cases.addWhenColumnNotNull(
generateTableAlias( alias, notNullColumnTableNumbers[i] ),
notNullColumnNames[i],
discriminatorValues[i]
);
}
return cases;
|
public java.lang.String | filterFragment(java.lang.String alias)
return hasWhere() ?
" and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
"";
|
public java.lang.String | fromTableFragment(java.lang.String alias)
return getTableName() + ' " + alias;
|
public java.lang.String | generateFilterConditionAlias(java.lang.String rootAlias)
return generateTableAlias( rootAlias, tableSpan-1 );
|
public java.lang.String[] | getConstraintOrderedTableNameClosure()
return constraintOrderedTableNames;
|
public java.lang.String[][] | getContraintOrderedTableKeyColumnClosure()
return constraintOrderedKeyColumnNames;
|
public java.lang.String | getDiscriminatorSQLValue()
return discriminatorSQLString;
|
public org.hibernate.type.Type | getDiscriminatorType()
return Hibernate.INTEGER;
|
public java.lang.String[] | getIdentifierColumnNames()
return tableKeyColumns[0];
|
protected java.lang.String[] | getKeyColumns(int j)
return naturalOrderTableKeyColumns[j];
|
public java.io.Serializable[] | getPropertySpaces()
return spaces; // don't need subclass tables, because they can't appear in conditions
|
public java.lang.String | getPropertyTableName(java.lang.String propertyName)
Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
if ( index == null ) {
return null;
}
return tableNames[ propertyTableNumbers[ index.intValue() ] ];
|
protected int[] | getPropertyTableNumbers()
return naturalOrderPropertyTableNumbers;
|
protected int[] | getPropertyTableNumbersInSelect()
return propertyTableNumbers;
|
public java.lang.String | getRootTableAlias(java.lang.String drivingAlias)
return generateTableAlias( drivingAlias, getTableId( getRootTableName(), tableNames ) );
|
public java.lang.String | getRootTableName()
return naturalOrderTableNames[0];
|
protected int[] | getSubclassColumnTableNumberClosure()
return subclassColumnTableNumberClosure;
|
public java.lang.String | getSubclassForDiscriminatorValue(java.lang.Object value)
return (String) subclassesByDiscriminatorValue.get(value);
|
protected int[] | getSubclassFormulaTableNumberClosure()
return subclassFormulaTableNumberClosure;
|
public Declarer | getSubclassPropertyDeclarer(java.lang.String propertyPath)
if ( "class".equals( propertyPath ) ) {
// special case where we need to force incloude all subclass joins
return Declarer.SUBCLASS;
}
return super.getSubclassPropertyDeclarer( propertyPath );
|
public java.lang.String | getSubclassPropertyTableName(int i)
return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
|
protected int | getSubclassPropertyTableNumber(int i)
return subclassPropertyTableNumberClosure[i];
|
protected java.lang.String[] | getSubclassTableKeyColumns(int j)
return subclassTableKeyColumnClosure[j];
|
public java.lang.String | getSubclassTableName(int j)
return subclassTableNameClosure[j];
|
public int | getSubclassTableSpan()
return subclassTableNameClosure.length;
|
private static int | getTableId(java.lang.String tableName, java.lang.String[] tables)
for ( int j=0; j<tables.length; j++ ) {
if ( tableName.equals( tables[j] ) ) {
return j;
}
}
throw new AssertionFailure("Table " + tableName + " not found");
|
public java.lang.String | getTableName()
return tableNames[0];
|
protected java.lang.String | getTableName(int j)
return naturalOrderTableNames[j];
|
public int | getTableSpan()
return tableSpan;
|
protected boolean | isClassOrSuperclassTable(int j)
return isClassOrSuperclassTable[j];
|
public boolean | isMultiTable()
return true;
|
protected boolean | isPropertyOfTable(int property, int j)
return naturalOrderPropertyTableNumbers[property]==j;
|
protected boolean | isTableCascadeDeleteEnabled(int j)
return naturalOrderCascadeDeleteEnabled[j];
|
private static final void | reverse(java.lang.Object[] objects, int len)Load an instance using either the forUpdateLoader or the outer joining loader,
depending upon the value of the lock parameter
Object[] temp = new Object[len];
for (int i=0; i<len; i++) {
temp[i] = objects[len-i-1];
}
for (int i=0; i<len; i++) {
objects[i] = temp[i];
}
|
private static final java.lang.String[] | reverse(java.lang.String[] objects)
int len = objects.length;
String[] temp = new String[len];
for (int i=0; i<len; i++) {
temp[i] = objects[len-i-1];
}
return temp;
|
private static final java.lang.String[][] | reverse(java.lang.String[][] objects)
int len = objects.length;
String[][] temp = new String[len][];
for (int i=0; i<len; i++) {
temp[i] = objects[len-i-1];
}
return temp;
|
public java.lang.String[] | toColumns(java.lang.String alias, java.lang.String propertyName)
if ( ENTITY_CLASS.equals(propertyName) ) {
// This doesn't actually seem to work but it *might*
// work on some dbs. Also it doesn't work if there
// are multiple columns of results because it
// is not accounting for the suffix:
// return new String[] { getDiscriminatorColumnName() };
return new String[] { discriminatorFragment(alias).toFragmentString() };
}
else {
return super.toColumns(alias, propertyName);
}
|