FileDocCategorySizeDatePackage
UnionSubclassEntityPersister.javaAPI DocHibernate 3.2.513691Thu Jun 22 14:51:44 BST 2006org.hibernate.persister.entity

UnionSubclassEntityPersister

public class UnionSubclassEntityPersister extends AbstractEntityPersister
Implementation of the "table-per-concrete-class" or "roll-down" mapping strategy for an entity and its inheritence hierarchy.
author
Gavin King

Fields Summary
private final String
subquery
private final String
tableName
private final String[]
subclassClosure
private final String[]
spaces
private final String[]
subclassSpaces
private final String
discriminatorSQLValue
private final Map
subclassByDiscriminatorValue
private final String[]
constraintOrderedTableNames
private final String[]
constraintOrderedKeyColumnNames
Constructors Summary
public UnionSubclassEntityPersister(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);
		
		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 Summary
protected voidaddDiscriminatorToSelect(org.hibernate.sql.SelectFragment select, java.lang.String name, java.lang.String suffix)

		select.addColumn( name, getDiscriminatorColumnName(),  getDiscriminatorAlias() );
	
public java.lang.StringfilterFragment(java.lang.String name)

		return hasWhere() ?
			" and " + getSQLWhereString(name) :
			"";
	
public java.lang.StringfromTableFragment(java.lang.String name)

		return getTableName() + ' "  + name;
	
protected java.lang.StringgenerateSelectString(org.hibernate.LockMode lockMode)
Generate the SQL that selects a row by id

		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();
	
protected java.lang.StringgenerateSubquery(org.hibernate.mapping.PersistentClass model, org.hibernate.engine.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 java.lang.String[]getConstraintOrderedTableNameClosure()

			return constraintOrderedTableNames;
	
public java.lang.String[][]getContraintOrderedTableKeyColumnClosure()

		return constraintOrderedKeyColumnNames;
	
protected java.lang.StringgetDiscriminatorFormula()

		return null;
	
public java.lang.StringgetDiscriminatorSQLValue()

		return discriminatorSQLValue;
	
public org.hibernate.type.TypegetDiscriminatorType()

		return Hibernate.INTEGER;
	
protected java.lang.String[]getKeyColumns(int j)

		return getIdentifierColumnNames();
	
public java.io.Serializable[]getPropertySpaces()

		return spaces;
	
public java.lang.StringgetPropertyTableName(java.lang.String propertyName)

		//TODO: check this....
		return getTableName();
	
protected int[]getPropertyTableNumbers()

		return new int[ getPropertySpan() ];
	
protected int[]getPropertyTableNumbersInSelect()

		return new int[ getPropertySpan() ];
	
public java.io.Serializable[]getQuerySpaces()

		return subclassSpaces;
	
public java.lang.String[]getSubclassClosure()

		return subclassClosure;
	
protected int[]getSubclassColumnTableNumberClosure()

		return new int[ getSubclassColumnClosure().length ];
	
public java.lang.StringgetSubclassForDiscriminatorValue(java.lang.Object value)

		return (String) subclassByDiscriminatorValue.get(value);
	
protected int[]getSubclassFormulaTableNumberClosure()

		return new int[ getSubclassFormulaClosure().length ];
	
public java.lang.StringgetSubclassPropertyTableName(int i)

		return getTableName();//ie. the subquery! yuck!
	
protected intgetSubclassPropertyTableNumber(int i)

		return 0;
	
public intgetSubclassPropertyTableNumber(java.lang.String propertyName)

		return 0;
	
protected java.lang.String[]getSubclassTableKeyColumns(int j)

		if (j!=0) throw new AssertionFailure("only one table");
		return getIdentifierColumnNames();
	
public java.lang.StringgetSubclassTableName(int j)

		if (j!=0) throw new AssertionFailure("only one table");
		return tableName;
	
public intgetSubclassTableSpan()

		return 1;
	
protected boolean[]getTableHasColumns()

		return new boolean[] { true };
	
protected java.lang.StringgetTableName(int j)

		return tableName;
	
public java.lang.StringgetTableName()

		return subquery;
	
public intgetTableSpan()

		return 1;
	
protected booleanisClassOrSuperclassTable(int j)

		if (j!=0) throw new AssertionFailure("only one table");
		return true;
	
protected booleanisDiscriminatorFormula()

		return false;
	
public booleanisMultiTable()

		// This could also just be true all the time...
		return isAbstract() || hasSubclasses();
	
protected booleanisPropertyOfTable(int property, int j)

		return true;
	
protected booleanisTableCascadeDeleteEnabled(int j)

		return false;