FileDocCategorySizeDatePackage
AbstractCollectionPersister.javaAPI DocHibernate 3.2.553448Thu Nov 30 14:50:48 GMT 2006org.hibernate.persister.collection

AbstractCollectionPersister

public abstract class AbstractCollectionPersister extends Object implements org.hibernate.metadata.CollectionMetadata, SQLLoadableCollection
Base implementation of the QueryableCollection interface.
author
Gavin King
see
BasicCollectionPersister
see
OneToManyPersister

Fields Summary
private final String
role
private final String
sqlDeleteString
private final String
sqlInsertRowString
private final String
sqlUpdateRowString
private final String
sqlDeleteRowString
private final String
sqlSelectSizeString
private final String
sqlSelectRowByIndexString
private final String
sqlDetectRowByIndexString
private final String
sqlDetectRowByElementString
private final String
sqlOrderByString
protected final String
sqlWhereString
private final String
sqlOrderByStringTemplate
private final String
sqlWhereStringTemplate
private final boolean
hasOrder
protected final boolean
hasWhere
private final int
baseIndex
private final String
nodeName
private final String
elementNodeName
private final String
indexNodeName
protected final boolean
indexContainsFormula
protected final boolean
elementIsPureFormula
private final org.hibernate.type.Type
keyType
private final org.hibernate.type.Type
indexType
protected final org.hibernate.type.Type
elementType
private final org.hibernate.type.Type
identifierType
protected final String[]
keyColumnNames
protected final String[]
indexColumnNames
protected final String[]
indexFormulaTemplates
protected final String[]
indexFormulas
protected final boolean[]
indexColumnIsSettable
protected final String[]
elementColumnNames
protected final String[]
elementFormulaTemplates
protected final String[]
elementFormulas
protected final boolean[]
elementColumnIsSettable
protected final boolean[]
elementColumnIsInPrimaryKey
protected final String[]
indexColumnAliases
protected final String[]
elementColumnAliases
protected final String[]
keyColumnAliases
protected final String
identifierColumnName
private final String
identifierColumnAlias
protected final String
qualifiedTableName
private final String
queryLoaderName
private final boolean
isPrimitiveArray
private final boolean
isArray
protected final boolean
hasIndex
protected final boolean
hasIdentifier
private final boolean
isLazy
private final boolean
isExtraLazy
private final boolean
isInverse
private final boolean
isMutable
private final boolean
isVersioned
protected final int
batchSize
private final org.hibernate.FetchMode
fetchMode
private final boolean
hasOrphanDelete
private final boolean
subselectLoadable
private final Class
elementClass
private final String
entityName
private final org.hibernate.dialect.Dialect
dialect
private final org.hibernate.exception.SQLExceptionConverter
sqlExceptionConverter
private final org.hibernate.engine.SessionFactoryImplementor
factory
private final org.hibernate.persister.entity.EntityPersister
ownerPersister
private final org.hibernate.id.IdentifierGenerator
identifierGenerator
private final org.hibernate.persister.entity.PropertyMapping
elementPropertyMapping
private final org.hibernate.persister.entity.EntityPersister
elementPersister
private final org.hibernate.cache.CacheConcurrencyStrategy
cache
private final org.hibernate.type.CollectionType
collectionType
private org.hibernate.loader.collection.CollectionInitializer
initializer
private final org.hibernate.cache.entry.CacheEntryStructure
cacheEntryStructure
private final org.hibernate.util.FilterHelper
filterHelper
private final org.hibernate.util.FilterHelper
manyToManyFilterHelper
private final String
manyToManyWhereString
private final String
manyToManyWhereTemplate
private final String
manyToManyOrderByString
private final String
manyToManyOrderByTemplate
private final boolean
insertCallable
private final boolean
updateCallable
private final boolean
deleteCallable
private final boolean
deleteAllCallable
private org.hibernate.engine.ExecuteUpdateResultCheckStyle
insertCheckStyle
private org.hibernate.engine.ExecuteUpdateResultCheckStyle
updateCheckStyle
private org.hibernate.engine.ExecuteUpdateResultCheckStyle
deleteCheckStyle
private org.hibernate.engine.ExecuteUpdateResultCheckStyle
deleteAllCheckStyle
private final Serializable[]
spaces
private Map
collectionPropertyColumnAliases
private Map
collectionPropertyColumnNames
private static final Log
log
Constructors Summary
public AbstractCollectionPersister(org.hibernate.mapping.Collection collection, org.hibernate.cache.CacheConcurrencyStrategy cache, org.hibernate.cfg.Configuration cfg, org.hibernate.engine.SessionFactoryImplementor factory)


	 
			  
			  
			  
			  
	   

		this.factory = factory;
		this.cache = cache;
		if ( factory.getSettings().isStructuredCacheEntriesEnabled() ) {
			cacheEntryStructure = collection.isMap() ? 
					(CacheEntryStructure) new StructuredMapCacheEntry() : 
					(CacheEntryStructure) new StructuredCollectionCacheEntry();
		}
		else {
			cacheEntryStructure = new UnstructuredCacheEntry();
		}
		
		dialect = factory.getDialect();
		sqlExceptionConverter = factory.getSQLExceptionConverter();
		collectionType = collection.getCollectionType();
		role = collection.getRole();
		entityName = collection.getOwnerEntityName();
		ownerPersister = factory.getEntityPersister(entityName);
		queryLoaderName = collection.getLoaderName();
		nodeName = collection.getNodeName();
		isMutable = collection.isMutable();

		Table table = collection.getCollectionTable();
		fetchMode = collection.getElement().getFetchMode();
		elementType = collection.getElement().getType();
		//isSet = collection.isSet();
		//isSorted = collection.isSorted();
		isPrimitiveArray = collection.isPrimitiveArray();
		isArray = collection.isArray();
		subselectLoadable = collection.isSubselectLoadable();
		
		qualifiedTableName = table.getQualifiedName( 
				dialect,
				factory.getSettings().getDefaultCatalogName(),
				factory.getSettings().getDefaultSchemaName() 
			);

		int spacesSize = 1 + collection.getSynchronizedTables().size();
		spaces = new String[spacesSize];
		spaces[0] = qualifiedTableName;
		Iterator iter = collection.getSynchronizedTables().iterator();
		for ( int i = 1; i < spacesSize; i++ ) {
			spaces[i] = (String) iter.next();
		}
		
		sqlOrderByString = collection.getOrderBy();
		hasOrder = sqlOrderByString != null;
		sqlOrderByStringTemplate = hasOrder ?
				Template.renderOrderByStringTemplate(sqlOrderByString, dialect, factory.getSqlFunctionRegistry()) :
				null;
		sqlWhereString = StringHelper.isNotEmpty( collection.getWhere() ) ? "( " + collection.getWhere() + ") " : null;
		hasWhere = sqlWhereString != null;
		sqlWhereStringTemplate = hasWhere ?
				Template.renderWhereStringTemplate(sqlWhereString, dialect, factory.getSqlFunctionRegistry()) :
				null;

		hasOrphanDelete = collection.hasOrphanDelete();

		int batch = collection.getBatchSize();
		if ( batch == -1 ) {
			batch = factory.getSettings().getDefaultBatchFetchSize();
		}
		batchSize = batch;

		isVersioned = collection.isOptimisticLocked();
		
		// KEY

		keyType = collection.getKey().getType();
		iter = collection.getKey().getColumnIterator();
		int keySpan = collection.getKey().getColumnSpan();
		keyColumnNames = new String[keySpan];
		keyColumnAliases = new String[keySpan];
		int k = 0;
		while ( iter.hasNext() ) {
			// NativeSQL: collect key column and auto-aliases
			Column col = ( (Column) iter.next() );
			keyColumnNames[k] = col.getQuotedName(dialect);
			keyColumnAliases[k] = col.getAlias(dialect);
			k++;
		}
		
		//unquotedKeyColumnNames = StringHelper.unQuote(keyColumnAliases);

		//ELEMENT

		String elemNode = collection.getElementNodeName();
		if ( elementType.isEntityType() ) {
			String entityName = ( (EntityType) elementType ).getAssociatedEntityName();
			elementPersister = factory.getEntityPersister(entityName);
			if ( elemNode==null ) {
				elemNode = cfg.getClassMapping(entityName).getNodeName();
			}
			// NativeSQL: collect element column and auto-aliases
			
		}
		else {
			elementPersister = null;
		}		
		elementNodeName = elemNode;

		int elementSpan = collection.getElement().getColumnSpan();
		elementColumnAliases = new String[elementSpan];
		elementColumnNames = new String[elementSpan];
		elementFormulaTemplates = new String[elementSpan];
		elementFormulas = new String[elementSpan];
		elementColumnIsSettable = new boolean[elementSpan];
		elementColumnIsInPrimaryKey = new boolean[elementSpan];
		boolean isPureFormula = true;
		boolean hasNotNullableColumns = false;
		int j = 0;
		iter = collection.getElement().getColumnIterator();
		while ( iter.hasNext() ) {
			Selectable selectable = (Selectable) iter.next();
			elementColumnAliases[j] = selectable.getAlias(dialect);
			if ( selectable.isFormula() ) {
				Formula form = (Formula) selectable;
				elementFormulaTemplates[j] = form.getTemplate(dialect, factory.getSqlFunctionRegistry());
				elementFormulas[j] = form.getFormula();
			}
			else {
				Column col = (Column) selectable;
				elementColumnNames[j] = col.getQuotedName(dialect);
				elementColumnIsSettable[j] = true;
				elementColumnIsInPrimaryKey[j] = !col.isNullable();
				if ( !col.isNullable() ) {
					hasNotNullableColumns = true;
				}
				isPureFormula = false;
			}
			j++;
		}
		elementIsPureFormula = isPureFormula;
		
		//workaround, for backward compatibility of sets with no
		//not-null columns, assume all columns are used in the
		//row locator SQL
		if ( !hasNotNullableColumns ) {
			Arrays.fill( elementColumnIsInPrimaryKey, true );
		}


		// INDEX AND ROW SELECT

		hasIndex = collection.isIndexed();
		if (hasIndex) {
			// NativeSQL: collect index column and auto-aliases
			IndexedCollection indexedCollection = (IndexedCollection) collection;
			indexType = indexedCollection.getIndex().getType();
			int indexSpan = indexedCollection.getIndex().getColumnSpan();
			iter = indexedCollection.getIndex().getColumnIterator();
			indexColumnNames = new String[indexSpan];
			indexFormulaTemplates = new String[indexSpan];
			indexFormulas = new String[indexSpan];
			indexColumnIsSettable = new boolean[indexSpan];
			indexColumnAliases = new String[indexSpan];
			int i = 0;
			boolean hasFormula = false;
			while ( iter.hasNext() ) {
				Selectable s = (Selectable) iter.next();
				indexColumnAliases[i] = s.getAlias(dialect);
				if ( s.isFormula() ) {
					Formula indexForm = (Formula) s;
					indexFormulaTemplates[i] = indexForm.getTemplate(dialect, factory.getSqlFunctionRegistry());
					indexFormulas[i] = indexForm.getFormula();
					hasFormula = true;
				}
				else {
					Column indexCol = (Column) s;
					indexColumnNames[i] = indexCol.getQuotedName(dialect);
					indexColumnIsSettable[i] = true;
				}
				i++;
			}
			indexContainsFormula = hasFormula;
			baseIndex = indexedCollection.isList() ? 
					( (List) indexedCollection ).getBaseIndex() : 0;

			indexNodeName = indexedCollection.getIndexNodeName(); 

		}
		else {
			indexContainsFormula = false;
			indexColumnIsSettable = null;
			indexFormulaTemplates = null;
			indexFormulas = null;
			indexType = null;
			indexColumnNames = null;
			indexColumnAliases = null;
			baseIndex = 0;
			indexNodeName = null;
		}
		
		hasIdentifier = collection.isIdentified();
		if (hasIdentifier) {
			if ( collection.isOneToMany() ) {
				throw new MappingException( "one-to-many collections with identifiers are not supported" );
			}
			IdentifierCollection idColl = (IdentifierCollection) collection;
			identifierType = idColl.getIdentifier().getType();
			iter = idColl.getIdentifier().getColumnIterator();
			Column col = ( Column ) iter.next();
			identifierColumnName = col.getQuotedName(dialect);
			identifierColumnAlias = col.getAlias(dialect);
			//unquotedIdentifierColumnName = identifierColumnAlias;
			identifierGenerator = idColl.getIdentifier().createIdentifierGenerator( 
					factory.getDialect(),
					factory.getSettings().getDefaultCatalogName(),
					factory.getSettings().getDefaultSchemaName(),
					null
				);
		}
		else {
			identifierType = null;
			identifierColumnName = null;
			identifierColumnAlias = null;
			//unquotedIdentifierColumnName = null;
			identifierGenerator = null;
		}
		
		//GENERATE THE SQL:
				
		//sqlSelectString = sqlSelectString();
		//sqlSelectRowString = sqlSelectRowString();

		if ( collection.getCustomSQLInsert() == null ) {
			sqlInsertRowString = generateInsertRowString();
			insertCallable = false;
			insertCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
		}
		else {
			sqlInsertRowString = collection.getCustomSQLInsert();
			insertCallable = collection.isCustomInsertCallable();
			insertCheckStyle = collection.getCustomSQLInsertCheckStyle() == null
					? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLInsert(), insertCallable )
		            : collection.getCustomSQLInsertCheckStyle();
		}

		if ( collection.getCustomSQLUpdate() == null ) {
			sqlUpdateRowString = generateUpdateRowString();
			updateCallable = false;
			updateCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
		}
		else {
			sqlUpdateRowString = collection.getCustomSQLUpdate();
			updateCallable = collection.isCustomUpdateCallable();
			updateCheckStyle = collection.getCustomSQLUpdateCheckStyle() == null
					? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLUpdate(), insertCallable )
		            : collection.getCustomSQLUpdateCheckStyle();
		}

		if ( collection.getCustomSQLDelete() == null ) {
			sqlDeleteRowString = generateDeleteRowString();
			deleteCallable = false;
			deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
		}
		else {
			sqlDeleteRowString = collection.getCustomSQLDelete();
			deleteCallable = collection.isCustomDeleteCallable();
			deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
		}

		if ( collection.getCustomSQLDeleteAll() == null ) {
			sqlDeleteString = generateDeleteString();
			deleteAllCallable = false;
			deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
		}
		else {
			sqlDeleteString = collection.getCustomSQLDeleteAll();
			deleteAllCallable = collection.isCustomDeleteAllCallable();
			deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
		}

		sqlSelectSizeString = generateSelectSizeString(  collection.isIndexed() && !collection.isMap() );
		sqlDetectRowByIndexString = generateDetectRowByIndexString();
		sqlDetectRowByElementString = generateDetectRowByElementString();
		sqlSelectRowByIndexString = generateSelectRowByIndexString();
		
		logStaticSQL();
		
		isLazy = collection.isLazy();
		isExtraLazy = collection.isExtraLazy();

		isInverse = collection.isInverse();

		if ( collection.isArray() ) {
			elementClass = ( (org.hibernate.mapping.Array) collection ).getElementClass();
		}
		else {
			// for non-arrays, we don't need to know the element class
			elementClass = null; //elementType.returnedClass();
		}

		if ( elementType.isComponentType() ) {
			elementPropertyMapping = new CompositeElementPropertyMapping( 
					elementColumnNames,
					elementFormulaTemplates,
					(AbstractComponentType) elementType,
					factory 
				);
		}
		else if ( !elementType.isEntityType() ) {
			elementPropertyMapping = new ElementPropertyMapping( 
					elementColumnNames,
					elementType 
				);
		}
		else {
			if ( elementPersister instanceof PropertyMapping ) { //not all classpersisters implement PropertyMapping!
				elementPropertyMapping = (PropertyMapping) elementPersister;
			}
			else {
				elementPropertyMapping = new ElementPropertyMapping( 
						elementColumnNames,
						elementType 
					);
			}
		}
			
		// Handle any filters applied to this collection
		filterHelper = new FilterHelper( collection.getFilterMap(), dialect, factory.getSqlFunctionRegistry() );

		// Handle any filters applied to this collection for many-to-many
		manyToManyFilterHelper = new FilterHelper( collection.getManyToManyFilterMap(), dialect, factory.getSqlFunctionRegistry() );
		manyToManyWhereString = StringHelper.isNotEmpty( collection.getManyToManyWhere() ) ?
				"( " + collection.getManyToManyWhere() + " )" :
				null;
		manyToManyWhereTemplate = manyToManyWhereString == null ?
				null :
				Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );
		manyToManyOrderByString = collection.getManyToManyOrdering();
		manyToManyOrderByTemplate = manyToManyOrderByString == null
				? null
	            : Template.renderOrderByStringTemplate( manyToManyOrderByString, factory.getDialect(), factory.getSqlFunctionRegistry() );

		initCollectionPropertyMap();
	
Methods Summary
protected voidappendElementColumns(org.hibernate.sql.SelectFragment frag, java.lang.String elemAlias)

		for ( int i=0; i<elementColumnIsSettable.length; i++ ) {
			if ( elementColumnIsSettable[i] ) {
				frag.addColumn( elemAlias, elementColumnNames[i], elementColumnAliases[i] );
			}
			else {
				frag.addFormula( elemAlias, elementFormulaTemplates[i], elementColumnAliases[i] );
			}
		}
	
protected voidappendIdentifierColumns(org.hibernate.sql.SelectFragment frag, java.lang.String alias)

		if ( hasIdentifier ) {
			frag.addColumn( alias, identifierColumnName, identifierColumnAlias );
		}
	
protected voidappendIndexColumns(org.hibernate.sql.SelectFragment frag, java.lang.String alias)

		if ( hasIndex ) {
			for ( int i=0; i<indexColumnIsSettable.length; i++ ) {
				if ( indexColumnIsSettable[i] ) {
					frag.addColumn( alias, indexColumnNames[i], indexColumnAliases[i] );
				}
				else {
					frag.addFormula( alias, indexFormulaTemplates[i], indexColumnAliases[i] );
				}
			}
		}
	
protected abstract org.hibernate.loader.collection.CollectionInitializercreateCollectionInitializer(java.util.Map enabledFilters)

protected abstract org.hibernate.loader.collection.CollectionInitializercreateSubselectInitializer(org.hibernate.engine.SubselectFetch subselect, org.hibernate.engine.SessionImplementor session)

protected java.lang.ObjectdecrementIndexByBase(java.lang.Object index)

		if (baseIndex!=0) {
			index = new Integer( ( (Integer) index ).intValue() - baseIndex );
		}
		return index;
	
public voiddeleteRows(org.hibernate.collection.PersistentCollection collection, java.io.Serializable id, org.hibernate.engine.SessionImplementor session)


		if ( !isInverse && isRowDeleteEnabled() ) {

			if ( log.isDebugEnabled() ) {
				log.debug( 
						"Deleting rows of collection: " + 
						MessageHelper.collectionInfoString( this, id, getFactory() ) 
					);
			}
			
			boolean deleteByIndex = !isOneToMany() && hasIndex && !indexContainsFormula;
			
			try {
				//delete all the deleted entries
				Iterator deletes = collection.getDeletes( this, !deleteByIndex );
				if ( deletes.hasNext() ) {
					int offset = 1;
					int count = 0;
					while ( deletes.hasNext() ) {
						PreparedStatement st = null;
						Expectation expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
						boolean callable = isDeleteCallable();
						boolean useBatch = expectation.canBeBatched();
						String sql = getSQLDeleteRowString();

						if ( useBatch ) {
							if ( callable ) {
								st = session.getBatcher().prepareBatchCallableStatement( sql );
							}
							else {
								st = session.getBatcher().prepareBatchStatement( sql );
							}
						}
						else {
							if ( callable ) {
								st = session.getBatcher().prepareCallableStatement( sql );
							}
							else {
								st = session.getBatcher().prepareStatement( sql );
							}
						}

						try {
							expectation.prepare( st );

							Object entry = deletes.next();
							int loc = offset;
							if ( hasIdentifier ) {
								writeIdentifier( st, entry, loc, session );
							}
							else {
								loc = writeKey( st, id, loc, session );
								if ( deleteByIndex ) {
									writeIndexToWhere( st, entry, loc, session );
								}
								else {
									writeElementToWhere( st, entry, loc, session );
								}
							}

							if ( useBatch ) {
								session.getBatcher().addToBatch( expectation );
							}
							else {
								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
							}
							count++;
						}
						catch ( SQLException sqle ) {
							if ( useBatch ) {
								session.getBatcher().abortBatch( sqle );
							}
							throw sqle;
						}
						finally {
							if ( !useBatch ) {
								session.getBatcher().closeStatement( st );
							}
						}

						if ( log.isDebugEnabled() ) {
							log.debug( "done deleting collection rows: " + count + " deleted" );
						}
					}
				}
				else {
					if ( log.isDebugEnabled() ) {
						log.debug( "no rows to delete" );
					}
				}
			}
			catch ( SQLException sqle ) {
				throw JDBCExceptionHelper.convert(
				        sqlExceptionConverter,
				        sqle,
				        "could not delete collection rows: " + 
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLDeleteRowString()
					);
			}
		}
	
protected abstract intdoUpdateRows(java.io.Serializable key, org.hibernate.collection.PersistentCollection collection, org.hibernate.engine.SessionImplementor session)

public booleanelementExists(java.io.Serializable key, java.lang.Object element, org.hibernate.engine.SessionImplementor session)

		return exists(key, element, getElementType(), sqlDetectRowByElementString, session);
	
private booleanexists(java.io.Serializable key, java.lang.Object indexOrElement, org.hibernate.type.Type indexOrElementType, java.lang.String sql, org.hibernate.engine.SessionImplementor session)

		try {
			PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
			try {
				getKeyType().nullSafeSet(st, key, 1, session);
				indexOrElementType.nullSafeSet( st, indexOrElement, keyColumnNames.length + 1, session );
				ResultSet rs = st.executeQuery();
				try {
					return rs.next();
				}
				finally {
					rs.close();
				}
			}
			catch( TransientObjectException e ) {
				return false;
			}
			finally {
				session.getBatcher().closeStatement( st );
			}
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not check row existence: " + 
					MessageHelper.collectionInfoString( this, key, getFactory() ),
					sqlSelectSizeString
				);
		}
	
protected java.lang.StringfilterFragment(java.lang.String alias)

		return hasWhere() ? " and " + getSQLWhereString( alias ) : "";
	
public java.lang.StringfilterFragment(java.lang.String alias, java.util.Map enabledFilters)


		StringBuffer sessionFilterFragment = new StringBuffer();
		filterHelper.render( sessionFilterFragment, alias, enabledFilters );

		return sessionFilterFragment.append( filterFragment( alias ) ).toString();
	
protected abstract java.lang.StringgenerateDeleteRowString()

protected abstract java.lang.StringgenerateDeleteString()

protected java.lang.StringgenerateDetectRowByElementString()

		return new SimpleSelect(dialect)
				.setTableName( getTableName() )
				.addCondition( getKeyColumnNames(), "=?" )
				.addCondition( getElementColumnNames(), "=?" )
				.addCondition( elementFormulas, "=?" )
				.addColumn("1")
				.toStatementString();
	
protected java.lang.StringgenerateDetectRowByIndexString()

		if ( !hasIndex() ) {
			return null;
		}
		return new SimpleSelect(dialect)
				.setTableName( getTableName() )
				.addCondition( getKeyColumnNames(), "=?" )
				.addCondition( getIndexColumnNames(), "=?" )
				.addCondition( indexFormulas, "=?" )
				.addColumn("1")
				.toStatementString();
	
protected abstract java.lang.StringgenerateInsertRowString()

protected org.hibernate.sql.SelectFragmentgenerateSelectFragment(java.lang.String alias, java.lang.String columnSuffix)

		return new SelectFragment()
				.setSuffix( columnSuffix )
				.addColumns( alias, keyColumnNames, keyColumnAliases );
	
protected java.lang.StringgenerateSelectRowByIndexString()

		if ( !hasIndex() ) {
			return null;
		}
		return new SimpleSelect(dialect)
				.setTableName( getTableName() )
				.addCondition( getKeyColumnNames(), "=?" )
				.addCondition( getIndexColumnNames(), "=?" )
				.addCondition( indexFormulas, "=?" )
				.addColumns( getElementColumnNames(), elementColumnAliases )
				.addColumns( indexFormulas, indexColumnAliases )
				.toStatementString();
	
protected java.lang.StringgenerateSelectSizeString(boolean isIntegerIndexed)

		String selectValue = isIntegerIndexed ? 
			"max(" + getIndexColumnNames()[0] + ") + 1": //lists, arrays
			"count(" + getElementColumnNames()[0] + ")"; //sets, maps, bags
		return new SimpleSelect(dialect)
				.setTableName( getTableName() )
				.addCondition( getKeyColumnNames(), "=?" )
				.addColumn(selectValue)
				.toStatementString();
	
protected abstract java.lang.StringgenerateUpdateRowString()

protected org.hibernate.loader.collection.CollectionInitializergetAppropriateInitializer(java.io.Serializable key, org.hibernate.engine.SessionImplementor session)

		if ( queryLoaderName != null ) {
			//if there is a user-specified loader, return that
			//TODO: filters!?
			return initializer;
		}
		CollectionInitializer subselectInitializer = getSubselectInitializer( key, session );
		if ( subselectInitializer != null ) {
			return subselectInitializer;
		}
		else if ( session.getEnabledFilters().isEmpty() ) {
			return initializer;
		}
		else {
			return createCollectionInitializer( session.getEnabledFilters() );
		}
	
public org.hibernate.cache.CacheConcurrencyStrategygetCache()

		return cache;
	
public org.hibernate.cache.entry.CacheEntryStructuregetCacheEntryStructure()

		return cacheEntryStructure;
	
public org.hibernate.metadata.CollectionMetadatagetCollectionMetadata()

		return this;
	
public java.lang.String[]getCollectionPropertyColumnAliases(java.lang.String propertyName, java.lang.String suffix)

		String rawAliases[] = (String[]) collectionPropertyColumnAliases.get(propertyName);

		if ( rawAliases == null ) {
			return null;
		}
		
		String result[] = new String[rawAliases.length];
		for ( int i=0; i<rawAliases.length; i++ ) {
			result[i] = new Alias(suffix).toUnquotedAliasString( rawAliases[i] );
		}
		return result;
	
public java.io.Serializable[]getCollectionSpaces()

		return spaces;
	
public org.hibernate.type.CollectionTypegetCollectionType()

		return collectionType;
	
protected org.hibernate.engine.ExecuteUpdateResultCheckStylegetDeleteAllCheckStyle()

		return deleteAllCheckStyle;
	
protected org.hibernate.engine.ExecuteUpdateResultCheckStylegetDeleteCheckStyle()

		return deleteCheckStyle;
	
protected org.hibernate.dialect.DialectgetDialect()

		return dialect;
	
public java.lang.ObjectgetElementByIndex(java.io.Serializable key, java.lang.Object index, org.hibernate.engine.SessionImplementor session, java.lang.Object owner)

		try {
			PreparedStatement st = session.getBatcher().prepareSelectStatement(sqlSelectRowByIndexString);
			try {
				getKeyType().nullSafeSet(st, key, 1, session);
				getIndexType().nullSafeSet( st, incrementIndexByBase(index), keyColumnNames.length + 1, session );
				ResultSet rs = st.executeQuery();
				try {
					if ( rs.next() ) {
						return getElementType().nullSafeGet(rs, elementColumnAliases, session, owner);
					}
					else {
						return null;
					}
				}
				finally {
					rs.close();
				}
			}
			finally {
				session.getBatcher().closeStatement( st );
			}
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not read row: " + 
					MessageHelper.collectionInfoString( this, key, getFactory() ),
					sqlSelectSizeString
				);
		}
	
public java.lang.ClassgetElementClass()
Return the element class of an array, or null otherwise

 //needed by arrays
		return elementClass;
	
public java.lang.String[]getElementColumnAliases(java.lang.String suffix)

		return new Alias( suffix ).toAliasStrings( elementColumnAliases );
	
public java.lang.String[]getElementColumnNames(java.lang.String alias)

		return qualify(alias, elementColumnNames, elementFormulaTemplates);
	
public java.lang.String[]getElementColumnNames()

		return elementColumnNames; //TODO: something with formulas...
	
public java.lang.StringgetElementNodeName()

		return elementNodeName;
	
public org.hibernate.persister.entity.EntityPersistergetElementPersister()

		if ( elementPersister == null ) {
			throw new AssertionFailure( "not an association" );
		}
		return ( Loadable ) elementPersister;
	
public org.hibernate.type.TypegetElementType()

		return elementType;
	
public org.hibernate.engine.SessionFactoryImplementorgetFactory()

		return factory;
	
public org.hibernate.FetchModegetFetchMode()

		return fetchMode;
	
public java.lang.StringgetIdentifierColumnAlias(java.lang.String suffix)

		if ( hasIdentifier ) {
			return new Alias( suffix ).toAliasString( identifierColumnAlias );
		}
		else {
			return null;
		}
	
public java.lang.StringgetIdentifierColumnName()

		if ( hasIdentifier ) {
			return identifierColumnName;
		} else {
			return null;
		}
	
public org.hibernate.id.IdentifierGeneratorgetIdentifierGenerator()

		return identifierGenerator;
	
public org.hibernate.type.TypegetIdentifierType()

		return identifierType;
	
public java.lang.String[]getIndexColumnAliases(java.lang.String suffix)

		if ( hasIndex ) {
			return new Alias( suffix ).toAliasStrings( indexColumnAliases );
		}
		else {
			return null;
		}
	
public java.lang.String[]getIndexColumnNames()

		return indexColumnNames;
	
public java.lang.String[]getIndexColumnNames(java.lang.String alias)

		return qualify(alias, indexColumnNames, indexFormulaTemplates);

	
public java.lang.String[]getIndexFormulas()

		return indexFormulas;
	
public java.lang.StringgetIndexNodeName()

		return indexNodeName;
	
public org.hibernate.type.TypegetIndexType()

		return indexType;
	
protected org.hibernate.engine.ExecuteUpdateResultCheckStylegetInsertCheckStyle()

		return insertCheckStyle;
	
public java.lang.String[]getKeyColumnAliases(java.lang.String suffix)

		return new Alias( suffix ).toAliasStrings( keyColumnAliases );
	
public java.lang.String[]getKeyColumnNames()

		return keyColumnNames;
	
public org.hibernate.type.TypegetKeyType()

		return keyType;
	
public java.lang.StringgetManyToManyFilterFragment(java.lang.String alias, java.util.Map enabledFilters)

		StringBuffer buffer = new StringBuffer();
		manyToManyFilterHelper.render( buffer, alias, enabledFilters );

		if ( manyToManyWhereString != null ) {
			buffer.append( " and " )
					.append( StringHelper.replace( manyToManyWhereTemplate, Template.TEMPLATE, alias ) );
		}

		return buffer.toString();
	
public java.lang.StringgetManyToManyOrderByString(java.lang.String alias)

		if ( isManyToMany() && manyToManyOrderByString != null ) {
			return StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias );
		}
		else {
			return "";
		}
	
public java.lang.StringgetName()

		return getRole();
	
public java.lang.StringgetNodeName()

		return nodeName;
	
public java.lang.StringgetOwnerEntityName()

		return entityName;
	
public org.hibernate.persister.entity.EntityPersistergetOwnerEntityPersister()

		return ownerPersister;
	
public java.lang.StringgetRole()

		return role;
	
protected java.lang.StringgetSQLDeleteRowString()

		return sqlDeleteRowString;
	
protected java.lang.StringgetSQLDeleteString()

		return sqlDeleteString;
	
protected org.hibernate.exception.SQLExceptionConvertergetSQLExceptionConverter()

		return sqlExceptionConverter;
	
protected java.lang.StringgetSQLInsertRowString()

		return sqlInsertRowString;
	
public java.lang.StringgetSQLOrderByString(java.lang.String alias)

		return hasOrdering() ? 
			StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias ) : "";
	
protected java.lang.StringgetSQLUpdateRowString()

		return sqlUpdateRowString;
	
protected java.lang.StringgetSQLWhereString(java.lang.String alias)

		return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
	
public intgetSize(java.io.Serializable key, org.hibernate.engine.SessionImplementor session)

		try {
			PreparedStatement st = session.getBatcher().prepareSelectStatement(sqlSelectSizeString);
			try {
				getKeyType().nullSafeSet(st, key, 1, session);
				ResultSet rs = st.executeQuery();
				try {
					return rs.next() ? rs.getInt(1) - baseIndex : 0;
				}
				finally {
					rs.close();
				}
			}
			finally {
				session.getBatcher().closeStatement( st );
			}
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not retrieve collection size: " + 
					MessageHelper.collectionInfoString( this, key, getFactory() ),
					sqlSelectSizeString
				);
		}
	
private org.hibernate.loader.collection.CollectionInitializergetSubselectInitializer(java.io.Serializable key, org.hibernate.engine.SessionImplementor session)


		if ( !isSubselectLoadable() ) {
			return null;
		}
		
		final PersistenceContext persistenceContext = session.getPersistenceContext();
		
		SubselectFetch subselect = persistenceContext.getBatchFetchQueue()
			.getSubselect( new EntityKey( key, getOwnerEntityPersister(), session.getEntityMode() ) );
		
		if (subselect == null) {
			return null;
		}
		else {
			
			// Take care of any entities that might have
			// been evicted!	
			Iterator iter = subselect.getResult().iterator();
			while ( iter.hasNext() ) {
				if ( !persistenceContext.containsEntity( (EntityKey) iter.next() ) ) {
					iter.remove();
				}
			}	
			
			// Run a subquery loader
			return createSubselectInitializer( subselect, session );
		}
	
public java.lang.StringgetTableName()

		return qualifiedTableName;
	
public org.hibernate.type.TypegetType()

		return elementPropertyMapping.getType(); //==elementType ??
	
protected org.hibernate.engine.ExecuteUpdateResultCheckStylegetUpdateCheckStyle()

		return updateCheckStyle;
	
public booleanhasCache()

		return cache != null;
	
public booleanhasIndex()

		return hasIndex;
	
public booleanhasManyToManyOrdering()

		return isManyToMany() && manyToManyOrderByTemplate != null;
	
public booleanhasOrdering()

		return hasOrder;
	
public booleanhasOrphanDelete()

		return hasOrphanDelete;
	
public booleanhasWhere()

		return hasWhere;
	
protected java.lang.ObjectincrementIndexByBase(java.lang.Object index)

		if (baseIndex!=0) {
			index = new Integer( ( (Integer) index ).intValue() + baseIndex );
		}
		return index;
	
public booleanindexExists(java.io.Serializable key, java.lang.Object index, org.hibernate.engine.SessionImplementor session)

		return exists(key, incrementIndexByBase(index), getIndexType(), sqlDetectRowByIndexString, session);
	
public voidinitCollectionPropertyMap()


		initCollectionPropertyMap( "key", keyType, keyColumnAliases, keyColumnNames );
		initCollectionPropertyMap( "element", elementType, elementColumnAliases, elementColumnNames );
		if (hasIndex) {
			initCollectionPropertyMap( "index", indexType, indexColumnAliases, indexColumnNames );
		}
		if (hasIdentifier) {
			initCollectionPropertyMap( 
					"id", 
					identifierType, 
					new String[] { identifierColumnAlias }, 
					new String[] { identifierColumnName } 
				);
		}
	
private voidinitCollectionPropertyMap(java.lang.String aliasName, org.hibernate.type.Type type, java.lang.String[] columnAliases, java.lang.String[] columnNames)

		
		collectionPropertyColumnAliases.put(aliasName, columnAliases);
		collectionPropertyColumnNames.put(aliasName, columnNames);
	
		if( type.isComponentType() ) {
			AbstractComponentType ct = (AbstractComponentType) type;
			String[] propertyNames = ct.getPropertyNames();
			for (int i = 0; i < propertyNames.length; i++) {
				String name = propertyNames[i];
				collectionPropertyColumnAliases.put( aliasName + "." + name, columnAliases[i] );
				collectionPropertyColumnNames.put( aliasName + "." + name, columnNames[i] );
			}
		} 
		
	
public voidinitialize(java.io.Serializable key, org.hibernate.engine.SessionImplementor session)

		getAppropriateInitializer( key, session ).initialize( key, session );
	
public voidinsertRows(org.hibernate.collection.PersistentCollection collection, java.io.Serializable id, org.hibernate.engine.SessionImplementor session)


		if ( !isInverse && isRowInsertEnabled() ) {

			if ( log.isDebugEnabled() ) {
				log.debug( 
						"Inserting rows of collection: " + 
						MessageHelper.collectionInfoString( this, id, getFactory() ) 
					);
			}

			try {
				//insert all the new entries
				collection.preInsert( this );
				Iterator entries = collection.entries( this );
				Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
				boolean callable = isInsertCallable();
				boolean useBatch = expectation.canBeBatched();
				String sql = getSQLInsertRowString();
				int i = 0;
				int count = 0;
				while ( entries.hasNext() ) {
					int offset = 1;
					Object entry = entries.next();
					PreparedStatement st = null;
					if ( collection.needsInserting( entry, i, elementType ) ) {

						if ( useBatch ) {
							if ( st == null ) {
								if ( callable ) {
									st = session.getBatcher().prepareBatchCallableStatement( sql );
								}
								else {
									st = session.getBatcher().prepareBatchStatement( sql );
								}
							}
						}
						else {
							if ( callable ) {
								st = session.getBatcher().prepareCallableStatement( sql );
							}
							else {
								st = session.getBatcher().prepareStatement( sql );
							}
						}

						try {
							offset += expectation.prepare( st );
							//TODO: copy/paste from recreate()
							offset = writeKey( st, id, offset, session );
							if ( hasIdentifier ) {
								offset = writeIdentifier( st, collection.getIdentifier(entry, i), offset, session );
							}
							if ( hasIndex /*&& !indexIsFormula*/ ) {
								offset = writeIndex( st, collection.getIndex(entry, i, this), offset, session );
							}
							writeElement(st, collection.getElement(entry), offset, session );

							if ( useBatch ) {
								session.getBatcher().addToBatch( expectation );
							}
							else {
								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
							}
							collection.afterRowInsert( this, entry, i );
							count++;
						}
						catch ( SQLException sqle ) {
							if ( useBatch ) {
								session.getBatcher().abortBatch( sqle );
							}
							throw sqle;
						}
						finally {
							if ( !useBatch ) {
								session.getBatcher().closeStatement( st );
							}
						}
					}
					i++;
				}
				if ( log.isDebugEnabled() ) {
					log.debug( "done inserting rows: " + count + " inserted" );
				}
			}
			catch ( SQLException sqle ) {
				throw JDBCExceptionHelper.convert(
				        sqlExceptionConverter,
				        sqle,
				        "could not insert collection rows: " + 
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLInsertRowString()
					);
			}

		}
	
public booleanisAffectedByEnabledFilters(org.hibernate.engine.SessionImplementor session)

		return filterHelper.isAffectedBy( session.getEnabledFilters() ) ||
		        ( isManyToMany() && manyToManyFilterHelper.isAffectedBy( session.getEnabledFilters() ) );
	
public booleanisArray()

		return isArray;
	
public booleanisCollection()

		return true;
	
protected booleanisDeleteAllCallable()

		return deleteAllCallable;
	
protected booleanisDeleteCallable()

		return deleteCallable;
	
public booleanisExtraLazy()

		return isExtraLazy;
	
protected booleanisInsertCallable()

		return insertCallable;
	
public booleanisInverse()

		return isInverse;
	
public booleanisLazy()

		return isLazy;
	
public abstract booleanisManyToMany()

public booleanisMutable()

		return isMutable;
	
public booleanisPrimitiveArray()

		return isPrimitiveArray;
	
protected booleanisRowDeleteEnabled()

		return true;
	
protected booleanisRowInsertEnabled()

		return true;
	
public booleanisSubselectLoadable()

		return subselectLoadable;
	
protected booleanisUpdateCallable()

		return updateCallable;
	
public booleanisVersioned()

		return isVersioned && getOwnerEntityPersister().isVersioned();
	
protected voidlogStaticSQL()

		if ( log.isDebugEnabled() ) {
			log.debug( "Static SQL for collection: " + getRole() );
			if ( getSQLInsertRowString() != null ) {
				log.debug( " Row insert: " + getSQLInsertRowString() );
			}
			if ( getSQLUpdateRowString() != null ) {
				log.debug( " Row update: " + getSQLUpdateRowString() );
			}
			if ( getSQLDeleteRowString() != null ) {
				log.debug( " Row delete: " + getSQLDeleteRowString() );
			}
			if ( getSQLDeleteString() != null ) {
				log.debug( " One-shot delete: " + getSQLDeleteString() );
			}
		}
	
public java.lang.StringoneToManyFilterFragment(java.lang.String alias)

		return "";
	
public voidpostInstantiate()

		initializer = queryLoaderName == null ?
				createCollectionInitializer( CollectionHelper.EMPTY_MAP ) :
				new NamedQueryCollectionInitializer( queryLoaderName, this );
	
private static java.lang.String[]qualify(java.lang.String alias, java.lang.String[] columnNames, java.lang.String[] formulaTemplates)

		int span = columnNames.length;
		String[] result = new String[span];
		for (int i=0; i<span; i++) {
			if ( columnNames[i]==null ) {
				result[i] = StringHelper.replace( formulaTemplates[i], Template.TEMPLATE, alias );
			}
			else {
				result[i] = StringHelper.qualify( alias, columnNames[i] );
			}
		}
		return result;
	
public java.lang.ObjectreadElement(java.sql.ResultSet rs, java.lang.Object owner, java.lang.String[] aliases, org.hibernate.engine.SessionImplementor session)

		return getElementType().nullSafeGet( rs, aliases, session, owner );
	
public java.lang.ObjectreadIdentifier(java.sql.ResultSet rs, java.lang.String alias, org.hibernate.engine.SessionImplementor session)

		Object id = getIdentifierType().nullSafeGet( rs, alias, session, null );
		if ( id == null ) {
			throw new HibernateException( "null identifier column for collection: " + role );
		}
		return id;
	
public java.lang.ObjectreadIndex(java.sql.ResultSet rs, java.lang.String[] aliases, org.hibernate.engine.SessionImplementor session)

		Object index = getIndexType().nullSafeGet( rs, aliases, session, null );
		if ( index == null ) {
			throw new HibernateException( "null index column for collection: " + role );
		}
		index = decrementIndexByBase( index );
		return index;
	
public java.lang.ObjectreadKey(java.sql.ResultSet rs, java.lang.String[] aliases, org.hibernate.engine.SessionImplementor session)

		return getKeyType().nullSafeGet( rs, aliases, session, null );
	
public voidrecreate(org.hibernate.collection.PersistentCollection collection, java.io.Serializable id, org.hibernate.engine.SessionImplementor session)


		if ( !isInverse && isRowInsertEnabled() ) {

			if ( log.isDebugEnabled() ) {
				log.debug( 
						"Inserting collection: " + 
						MessageHelper.collectionInfoString( this, id, getFactory() ) 
					);
			}

			try {
				//create all the new entries
				Iterator entries = collection.entries(this);
				if ( entries.hasNext() ) {
					collection.preInsert( this );
					int i = 0;
					int count = 0;
					while ( entries.hasNext() ) {

						final Object entry = entries.next();
						if ( collection.entryExists( entry, i ) ) {
							int offset = 1;
							PreparedStatement st = null;
							Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
							boolean callable = isInsertCallable();
							boolean useBatch = expectation.canBeBatched();
							String sql = getSQLInsertRowString();

							if ( useBatch ) {
								if ( callable ) {
									st = session.getBatcher().prepareBatchCallableStatement( sql );
								}
								else {
									st = session.getBatcher().prepareBatchStatement( sql );
								}
							}
							else {
								if ( callable ) {
									st = session.getBatcher().prepareCallableStatement( sql );
								}
								else {
									st = session.getBatcher().prepareStatement( sql );
								}
							}


							try {
								offset+= expectation.prepare( st );

								//TODO: copy/paste from insertRows()
								int loc = writeKey( st, id, offset, session );
								if ( hasIdentifier ) {
									loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session );
								}
								if ( hasIndex /*&& !indexIsFormula*/ ) {
									loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session );
								}
								loc = writeElement(st, collection.getElement(entry), loc, session );

								if ( useBatch ) {
									session.getBatcher().addToBatch( expectation );
								}
								else {
									expectation.verifyOutcome( st.executeUpdate(), st, -1 );
								}

								collection.afterRowInsert( this, entry, i );
								count++;
							}
							catch ( SQLException sqle ) {
								if ( useBatch ) {
									session.getBatcher().abortBatch( sqle );
								}
								throw sqle;
							}
							finally {
								if ( !useBatch ) {
									session.getBatcher().closeStatement( st );
								}
							}

						}
						i++;
					}

					if ( log.isDebugEnabled() ) {
						log.debug( "done inserting collection: " + count + " rows inserted" );
					}

				}
				else {
					if ( log.isDebugEnabled() ) {
						log.debug( "collection was empty" );
					}
				}
			}
			catch ( SQLException sqle ) {
				throw JDBCExceptionHelper.convert(
				        sqlExceptionConverter,
				        sqle,
				        "could not insert collection: " + 
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLInsertRowString()
					);
			}
		}
	
public voidremove(java.io.Serializable id, org.hibernate.engine.SessionImplementor session)


		if ( !isInverse && isRowDeleteEnabled() ) {

			if ( log.isDebugEnabled() ) {
				log.debug( 
						"Deleting collection: " + 
						MessageHelper.collectionInfoString( this, id, getFactory() ) 
					);
			}

			// Remove all the old entries

			try {
				int offset = 1;
				PreparedStatement st = null;
				Expectation expectation = Expectations.appropriateExpectation( getDeleteAllCheckStyle() );
				boolean callable = isDeleteAllCallable();
				boolean useBatch = expectation.canBeBatched();
				String sql = getSQLDeleteString();
				if ( useBatch ) {
					if ( callable ) {
						st = session.getBatcher().prepareBatchCallableStatement( sql );
					}
					else {
						st = session.getBatcher().prepareBatchStatement( sql );
					}
				}
				else {
					if ( callable ) {
						st = session.getBatcher().prepareCallableStatement( sql );
					}
					else {
						st = session.getBatcher().prepareStatement( sql );
					}
				}


				try {
					offset+= expectation.prepare( st );

					writeKey( st, id, offset, session );
					if ( useBatch ) {
						session.getBatcher().addToBatch( expectation );
					}
					else {
						expectation.verifyOutcome( st.executeUpdate(), st, -1 );
					}
				}
				catch ( SQLException sqle ) {
					if ( useBatch ) {
						session.getBatcher().abortBatch( sqle );
					}
					throw sqle;
				}
				finally {
					if ( !useBatch ) {
						session.getBatcher().closeStatement( st );
					}
				}

				if ( log.isDebugEnabled() ) {
					log.debug( "done deleting collection" );
				}
			}
			catch ( SQLException sqle ) {
				throw JDBCExceptionHelper.convert(
				        sqlExceptionConverter,
				        sqle,
				        "could not delete collection: " + 
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLDeleteString()
					);
			}

		}

	
public java.lang.StringselectFragment(java.lang.String alias, java.lang.String columnSuffix)
Generate a list of collection index, key and element columns

		SelectFragment frag = generateSelectFragment( alias, columnSuffix );
		appendElementColumns( frag, alias );
		appendIndexColumns( frag, alias );
		appendIdentifierColumns( frag, alias );

		return frag.toFragmentString()
				.substring( 2 ); //strip leading ','
	
public java.lang.String[]toColumns(java.lang.String alias, java.lang.String propertyName)


		if ( "index".equals( propertyName ) ) {
			if ( isManyToMany() ) {
				throw new QueryException( "index() function not supported for many-to-many association" );
			}
			return StringHelper.qualify( alias, indexColumnNames );
		}

		return elementPropertyMapping.toColumns( alias, propertyName );
	
public java.lang.String[]toColumns(java.lang.String propertyName)


		if ( "index".equals( propertyName ) ) {
			if ( isManyToMany() ) {
				throw new QueryException( "index() function not supported for many-to-many association" );
			}
			return indexColumnNames;
		}

		return elementPropertyMapping.toColumns( propertyName );
	
public java.lang.StringtoString()

		return StringHelper.unqualify( getClass().getName() ) + '(" + role + ')";
	
public org.hibernate.type.TypetoType(java.lang.String propertyName)

		if ( "index".equals( propertyName ) ) {
			return indexType;
		}
		return elementPropertyMapping.toType( propertyName );
	
public voidupdateRows(org.hibernate.collection.PersistentCollection collection, java.io.Serializable id, org.hibernate.engine.SessionImplementor session)


		if ( !isInverse && collection.isRowUpdatePossible() ) {

			if ( log.isDebugEnabled() ) {
				log.debug( "Updating rows of collection: " + role + "#" + id );
			}

			//update all the modified entries
			int count = doUpdateRows( id, collection, session );

			if ( log.isDebugEnabled() ) {
				log.debug( "done updating rows: " + count + " updated" );
			}
		}
	
protected intwriteElement(java.sql.PreparedStatement st, java.lang.Object elt, int i, org.hibernate.engine.SessionImplementor session)
Write the element to a JDBC PreparedStatement

		getElementType().nullSafeSet(st, elt, i, elementColumnIsSettable, session);
		return i + ArrayHelper.countTrue(elementColumnIsSettable);

	
protected intwriteElementToWhere(java.sql.PreparedStatement st, java.lang.Object elt, int i, org.hibernate.engine.SessionImplementor session)
Write the element to a JDBC PreparedStatement

		if (elementIsPureFormula) {
			throw new AssertionFailure("cannot use a formula-based element in the where condition");
		}
		getElementType().nullSafeSet(st, elt, i, elementColumnIsInPrimaryKey, session);
		return i + elementColumnAliases.length;

	
public intwriteIdentifier(java.sql.PreparedStatement st, java.lang.Object id, int i, org.hibernate.engine.SessionImplementor session)
Write the identifier to a JDBC PreparedStatement

		
		getIdentifierType().nullSafeSet( st, id, i, session );
		return i + 1;
	
protected intwriteIndex(java.sql.PreparedStatement st, java.lang.Object index, int i, org.hibernate.engine.SessionImplementor session)
Write the index to a JDBC PreparedStatement

		getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, indexColumnIsSettable, session );
		return i + ArrayHelper.countTrue(indexColumnIsSettable);
	
protected intwriteIndexToWhere(java.sql.PreparedStatement st, java.lang.Object index, int i, org.hibernate.engine.SessionImplementor session)
Write the index to a JDBC PreparedStatement

		if (indexContainsFormula) {
			throw new AssertionFailure("cannot use a formula-based index in the where condition");
		}
		getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, session );
		return i + indexColumnAliases.length;
	
protected intwriteKey(java.sql.PreparedStatement st, java.io.Serializable key, int i, org.hibernate.engine.SessionImplementor session)
Write the key to a JDBC PreparedStatement

		
		if ( key == null ) {
			throw new NullPointerException( "null key for collection: " + role );  //an assertion
		}
		getKeyType().nullSafeSet( st, key, i, session );
		return i + keyColumnAliases.length;