alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (AbstractCollectionPersister.java)

This example Hibernate source code file (AbstractCollectionPersister.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

basicbatchkey, column, executeupdateresultcheckstyle, hibernateexception, io, jdbc, mappingexception, object, object, sessionimplementor, sessionimplementor, sql, sqlexception, sqlexception, string, string, type, util

The Hibernate AbstractCollectionPersister.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.persister.collection;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.jboss.logging.Logger;

import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.TransientObjectException;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.entry.CacheEntryStructure;
import org.hibernate.cache.spi.entry.StructuredCollectionCacheEntry;
import org.hibernate.cache.spi.entry.StructuredMapCacheEntry;
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.FilterHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.IdentifierCollection;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.List;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Alias;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.SimpleSelect;
import org.hibernate.sql.Template;
import org.hibernate.sql.ordering.antlr.ColumnMapper;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;


/**
 * Base implementation of the <tt>QueryableCollection interface.
 *
 * @author Gavin King
 * @see BasicCollectionPersister
 * @see OneToManyPersister
 */
public abstract class AbstractCollectionPersister
		implements CollectionMetadata, SQLLoadableCollection {

    private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class,
                                                                       AbstractCollectionPersister.class.getName());

    // TODO: encapsulate the protected instance variables!

	private final String role;

	//SQL statements
	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;

	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;

	//types
	private final Type keyType;
	private final Type indexType;
	protected final Type elementType;
	private final Type identifierType;

	//columns
	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[] elementColumnWriters;
	protected final String[] elementColumnReaders;
	protected final String[] elementColumnReaderTemplates;
	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;
	//private final String unquotedIdentifierColumnName;

	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 FetchMode fetchMode;
	private final boolean hasOrphanDelete;
	private final boolean subselectLoadable;

	//extra information about the element type
	private final Class elementClass;
	private final String entityName;

	private final Dialect dialect;
	private final SqlExceptionHelper sqlExceptionHelper;
	private final SessionFactoryImplementor factory;
	private final EntityPersister ownerPersister;
	private final IdentifierGenerator identifierGenerator;
	private final PropertyMapping elementPropertyMapping;
	private final EntityPersister elementPersister;
	private final CollectionRegionAccessStrategy cacheAccessStrategy;
	private final CollectionType collectionType;
	private CollectionInitializer initializer;

	private final CacheEntryStructure cacheEntryStructure;

	// dynamic filters for the collection
	private final FilterHelper filterHelper;

	// dynamic filters specifically for many-to-many inside the collection
	private final FilterHelper manyToManyFilterHelper;

	private final String manyToManyWhereString;
	private final String manyToManyWhereTemplate;

	private final boolean hasManyToManyOrder;
	private final String manyToManyOrderByTemplate;

	// custom sql
	private final boolean insertCallable;
	private final boolean updateCallable;
	private final boolean deleteCallable;
	private final boolean deleteAllCallable;
	private ExecuteUpdateResultCheckStyle insertCheckStyle;
	private ExecuteUpdateResultCheckStyle updateCheckStyle;
	private ExecuteUpdateResultCheckStyle deleteCheckStyle;
	private ExecuteUpdateResultCheckStyle deleteAllCheckStyle;

	private final Serializable[] spaces;

	private Map collectionPropertyColumnAliases = new HashMap();
	private Map collectionPropertyColumnNames = new HashMap();

	public AbstractCollectionPersister(
			final Collection collection,
			final CollectionRegionAccessStrategy cacheAccessStrategy,
			final Configuration cfg,
			final SessionFactoryImplementor factory) throws MappingException, CacheException {

		this.factory = factory;
		this.cacheAccessStrategy = cacheAccessStrategy;
		if ( factory.getSettings().isStructuredCacheEntriesEnabled() ) {
			cacheEntryStructure = collection.isMap() ?
					( CacheEntryStructure ) new StructuredMapCacheEntry() :
					( CacheEntryStructure ) new StructuredCollectionCacheEntry();
		}
		else {
			cacheEntryStructure = new UnstructuredCacheEntry();
		}

		dialect = factory.getDialect();
		sqlExceptionHelper = factory.getSQLExceptionHelper();
		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();
		}

		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,collection.getOwner().getRootTable());
			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];
		elementColumnWriters = new String[elementSpan];
		elementColumnReaders = new String[elementSpan];
		elementColumnReaderTemplates = 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);
				elementColumnWriters[j] = col.getWriteExpr();
				elementColumnReaders[j] = col.getReadExpr(dialect);
				elementColumnReaderTemplates[j] = col.getTemplate(dialect, factory.getSqlFunctionRegistry());
				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(
					cfg.getIdentifierGeneratorFactory(),
					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,
					elementColumnReaders,
					elementColumnReaderTemplates,
					elementFormulaTemplates,
					(CompositeType) 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
					);
			}
		}

		hasOrder = collection.getOrderBy() != null;
		if ( hasOrder ) {
			ColumnMapper mapper = new ColumnMapper() {
				public String[] map(String reference) {
					return elementPropertyMapping.toColumns( reference );
				}
			};
			sqlOrderByStringTemplate = Template.renderOrderByStringTemplate(
					collection.getOrderBy(),
					mapper,
					factory,
					dialect,
					factory.getSqlFunctionRegistry()
			);
		}
		else {
			sqlOrderByStringTemplate = null;
		}

		// 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() );

		hasManyToManyOrder = collection.getManyToManyOrdering() != null;
		if ( hasManyToManyOrder ) {
			ColumnMapper mapper = new ColumnMapper() {
				public String[] map(String reference) {
					return elementPropertyMapping.toColumns( reference );
				}
			};
			manyToManyOrderByTemplate = Template.renderOrderByStringTemplate(
					collection.getManyToManyOrdering(),
					mapper,
					factory,
					dialect,
					factory.getSqlFunctionRegistry()
			);
		}
		else {
			manyToManyOrderByTemplate = null;
		}

		initCollectionPropertyMap();
	}

	public void postInstantiate() throws MappingException {
		initializer = queryLoaderName == null ?
				createCollectionInitializer( LoadQueryInfluencers.NONE ) :
				new NamedQueryCollectionInitializer( queryLoaderName, this );
	}

	protected void logStaticSQL() {
        if (LOG.isDebugEnabled()) {
            LOG.debugf("Static SQL for collection: %s", getRole());
            if (getSQLInsertRowString() != null) LOG.debugf(" Row insert: %s", getSQLInsertRowString());
            if (getSQLUpdateRowString() != null) LOG.debugf(" Row update: %s", getSQLUpdateRowString());
            if (getSQLDeleteRowString() != null) LOG.debugf(" Row delete: %s", getSQLDeleteRowString());
            if (getSQLDeleteString() != null) LOG.debugf(" One-shot delete: %s", getSQLDeleteString());
		}
	}

	public void initialize(Serializable key, SessionImplementor session) throws HibernateException {
		getAppropriateInitializer( key, session ).initialize( key, session );
	}

	protected CollectionInitializer getAppropriateInitializer(Serializable key, 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.getLoadQueryInfluencers() );
		}
	}

	private CollectionInitializer getSubselectInitializer(Serializable key, SessionImplementor session) {

		if ( !isSubselectLoadable() ) {
			return null;
		}

		final PersistenceContext persistenceContext = session.getPersistenceContext();

		SubselectFetch subselect = persistenceContext.getBatchFetchQueue()
				.getSubselect( session.generateEntityKey( key, getOwnerEntityPersister() ) );

		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 );
		}
	}

	protected abstract CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session);

	protected abstract CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers)
			throws MappingException;

	public CollectionRegionAccessStrategy getCacheAccessStrategy() {
		return cacheAccessStrategy;
	}

	public boolean hasCache() {
		return cacheAccessStrategy != null;
	}

	public CollectionType getCollectionType() {
		return collectionType;
	}

	protected String getSQLWhereString(String alias) {
		return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
	}

	public String getSQLOrderByString(String alias) {
		return hasOrdering()
				? StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias )
				: "";
	}

	public String getManyToManyOrderByString(String alias) {
		return hasManyToManyOrdering()
				? StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias )
				: "";
	}
	public FetchMode getFetchMode() {
		return fetchMode;
	}

	public boolean hasOrdering() {
		return hasOrder;
	}

	public boolean hasManyToManyOrdering() {
		return isManyToMany() && hasManyToManyOrder;
	}

	public boolean hasWhere() {
		return hasWhere;
	}

	protected String getSQLDeleteString() {
		return sqlDeleteString;
	}

	protected String getSQLInsertRowString() {
		return sqlInsertRowString;
	}

	protected String getSQLUpdateRowString() {
		return sqlUpdateRowString;
	}

	protected String getSQLDeleteRowString() {
		return sqlDeleteRowString;
	}

	public Type getKeyType() {
		return keyType;
	}

	public Type getIndexType() {
		return indexType;
	}

	public Type getElementType() {
		return elementType;
	}

	/**
	 * Return the element class of an array, or null otherwise
	 */
	public Class getElementClass() { //needed by arrays
		return elementClass;
	}

	public Object readElement(ResultSet rs, Object owner, String[] aliases, SessionImplementor session)
	throws HibernateException, SQLException {
		return getElementType().nullSafeGet( rs, aliases, session, owner );
	}

	public Object readIndex(ResultSet rs, String[] aliases, SessionImplementor session)
	throws HibernateException, SQLException {
		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;
	}

	protected Object decrementIndexByBase(Object index) {
		if (baseIndex!=0) {
			index = new Integer( ( (Integer) index ).intValue() - baseIndex );
		}
		return index;
	}

	public Object readIdentifier(ResultSet rs, String alias, SessionImplementor session)
	throws HibernateException, SQLException {
		Object id = getIdentifierType().nullSafeGet( rs, alias, session, null );
		if ( id == null ) {
			throw new HibernateException( "null identifier column for collection: " + role );
		}
		return id;
	}

	public Object readKey(ResultSet rs, String[] aliases, SessionImplementor session)
	throws HibernateException, SQLException {
		return getKeyType().nullSafeGet( rs, aliases, session, null );
	}

	/**
	 * Write the key to a JDBC <tt>PreparedStatement
	 */
	protected int writeKey(PreparedStatement st, Serializable key, int i, SessionImplementor session)
			throws HibernateException, SQLException {

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

	/**
	 * Write the element to a JDBC <tt>PreparedStatement
	 */
	protected int writeElement(PreparedStatement st, Object elt, int i, SessionImplementor session)
			throws HibernateException, SQLException {
		getElementType().nullSafeSet(st, elt, i, elementColumnIsSettable, session);
		return i + ArrayHelper.countTrue( elementColumnIsSettable );

	}

	/**
	 * Write the index to a JDBC <tt>PreparedStatement
	 */
	protected int writeIndex(PreparedStatement st, Object index, int i, SessionImplementor session)
			throws HibernateException, SQLException {
		getIndexType().nullSafeSet( st, incrementIndexByBase(index), i, indexColumnIsSettable, session );
		return i + ArrayHelper.countTrue(indexColumnIsSettable);
	}

	protected Object incrementIndexByBase(Object index) {
		if (baseIndex!=0) {
			index = new Integer( ( (Integer) index ).intValue() + baseIndex );
		}
		return index;
	}

	/**
	 * Write the element to a JDBC <tt>PreparedStatement
	 */
	protected int writeElementToWhere(PreparedStatement st, Object elt, int i, SessionImplementor session)
			throws HibernateException, SQLException {
		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;

	}

	/**
	 * Write the index to a JDBC <tt>PreparedStatement
	 */
	protected int writeIndexToWhere(PreparedStatement st, Object index, int i, SessionImplementor session)
			throws HibernateException, SQLException {
		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;
	}

	/**
	 * Write the identifier to a JDBC <tt>PreparedStatement
	 */
	public int writeIdentifier(PreparedStatement st, Object id, int i, SessionImplementor session)
			throws HibernateException, SQLException {

		getIdentifierType().nullSafeSet( st, id, i, session );
		return i + 1;
	}

	public boolean isPrimitiveArray() {
		return isPrimitiveArray;
	}

	public boolean isArray() {
		return isArray;
	}

	public String[] getKeyColumnAliases(String suffix) {
		return new Alias( suffix ).toAliasStrings( keyColumnAliases );
	}

	public String[] getElementColumnAliases(String suffix) {
		return new Alias( suffix ).toAliasStrings( elementColumnAliases );
	}

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

	public String getIdentifierColumnAlias(String suffix) {
		if ( hasIdentifier ) {
			return new Alias( suffix ).toAliasString( identifierColumnAlias );
		}
		else {
			return null;
		}
	}

	public String getIdentifierColumnName() {
		if ( hasIdentifier ) {
			return identifierColumnName;
		} else {
			return null;
		}
	}

	/**
	 * Generate a list of collection index, key and element columns
	 */
	public String selectFragment(String alias, String columnSuffix) {
		SelectFragment frag = generateSelectFragment( alias, columnSuffix );
		appendElementColumns( frag, alias );
		appendIndexColumns( frag, alias );
		appendIdentifierColumns( frag, alias );

		return frag.toFragmentString()
				.substring( 2 ); //strip leading ','
	}

	protected String generateSelectSizeString(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 String generateDetectRowByIndexString() {
		if ( !hasIndex() ) {
			return null;
		}
		return new SimpleSelect(dialect)
				.setTableName( getTableName() )
				.addCondition( getKeyColumnNames(), "=?" )
				.addCondition( getIndexColumnNames(), "=?" )
				.addCondition( indexFormulas, "=?" )
				.addColumn("1")
				.toStatementString();
	}

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

	protected String generateDetectRowByElementString() {
		return new SimpleSelect(dialect)
				.setTableName( getTableName() )
				.addCondition( getKeyColumnNames(), "=?" )
				.addCondition( getElementColumnNames(), "=?" )
				.addCondition( elementFormulas, "=?" )
				.addColumn("1")
				.toStatementString();
	}

	protected SelectFragment generateSelectFragment(String alias, String columnSuffix) {
		return new SelectFragment()
				.setSuffix( columnSuffix )
				.addColumns( alias, keyColumnNames, keyColumnAliases );
	}

	protected void appendElementColumns(SelectFragment frag, String elemAlias) {
		for ( int i=0; i<elementColumnIsSettable.length; i++ ) {
			if ( elementColumnIsSettable[i] ) {
				frag.addColumnTemplate( elemAlias, elementColumnReaderTemplates[i], elementColumnAliases[i] );
			}
			else {
				frag.addFormula( elemAlias, elementFormulaTemplates[i], elementColumnAliases[i] );
			}
		}
	}

	protected void appendIndexColumns(SelectFragment frag, 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 void appendIdentifierColumns(SelectFragment frag, String alias) {
		if ( hasIdentifier ) {
			frag.addColumn( alias, identifierColumnName, identifierColumnAlias );
		}
	}

	public String[] getIndexColumnNames() {
		return indexColumnNames;
	}

	public String[] getIndexFormulas() {
		return indexFormulas;
	}

	public String[] getIndexColumnNames(String alias) {
		return qualify(alias, indexColumnNames, indexFormulaTemplates);

	}

	public String[] getElementColumnNames(String alias) {
		return qualify(alias, elementColumnNames, elementFormulaTemplates);
	}

	private static String[] qualify(String alias, String[] columnNames, 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 String[] getElementColumnNames() {
		return elementColumnNames; //TODO: something with formulas...
	}

	public String[] getKeyColumnNames() {
		return keyColumnNames;
	}

	public boolean hasIndex() {
		return hasIndex;
	}

	public boolean isLazy() {
		return isLazy;
	}

	public boolean isInverse() {
		return isInverse;
	}

	public String getTableName() {
		return qualifiedTableName;
	}

	private BasicBatchKey removeBatchKey;

	public void remove(Serializable id, SessionImplementor session) throws HibernateException {
		if ( !isInverse && isRowDeleteEnabled() ) {

            if (LOG.isDebugEnabled()) LOG.debugf("Deleting collection: %s",
                                                 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 ( removeBatchKey == null ) {
						removeBatchKey = new BasicBatchKey(
								getRole() + "#REMOVE",
								expectation
						);
					}
					st = session.getTransactionCoordinator()
							.getJdbcCoordinator()
							.getBatch( removeBatchKey )
							.getBatchStatement( sql, callable );
				}
				else {
					st = session.getTransactionCoordinator()
							.getJdbcCoordinator()
							.getStatementPreparer()
							.prepareStatement( sql, callable );
				}


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

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

                LOG.debugf("Done deleting collection");
			}
			catch ( SQLException sqle ) {
				throw sqlExceptionHelper.convert(
				        sqle,
				        "could not delete collection: " +
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLDeleteString()
					);
			}

		}

	}

	private BasicBatchKey recreateBatchKey;

	public void recreate(PersistentCollection collection, Serializable id, SessionImplementor session)
			throws HibernateException {

		if ( !isInverse && isRowInsertEnabled() ) {

            if (LOG.isDebugEnabled()) LOG.debugf("Inserting collection: %s",
                                                 MessageHelper.collectionInfoString(this, id, getFactory()));

			try {
				//create all the new entries
				Iterator entries = collection.entries(this);
				if ( entries.hasNext() ) {
					Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
					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;
							boolean callable = isInsertCallable();
							boolean useBatch = expectation.canBeBatched();
							String sql = getSQLInsertRowString();

							if ( useBatch ) {
								if ( recreateBatchKey == null ) {
									recreateBatchKey = new BasicBatchKey(
											getRole() + "#RECREATE",
											expectation
									);
								}
								st = session.getTransactionCoordinator()
										.getJdbcCoordinator()
										.getBatch( recreateBatchKey )
										.getBatchStatement( sql, callable );
							}
							else {
								st = session.getTransactionCoordinator()
										.getJdbcCoordinator()
										.getStatementPreparer()
										.prepareStatement( sql, callable );
							}


							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.getTransactionCoordinator()
											.getJdbcCoordinator()
											.getBatch( recreateBatchKey )
											.addToBatch();
								}
								else {
									expectation.verifyOutcome( st.executeUpdate(), st, -1 );
								}

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

						}
						i++;
					}

                    LOG.debugf("Done inserting collection: %s rows inserted", count);

                } else LOG.debugf("Collection was empty");
			}
			catch ( SQLException sqle ) {
				throw sqlExceptionHelper.convert(
				        sqle,
				        "could not insert collection: " +
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLInsertRowString()
					);
			}
		}
	}

	protected boolean isRowDeleteEnabled() {
		return true;
	}

	private BasicBatchKey deleteBatchKey;

	public void deleteRows(PersistentCollection collection, Serializable id, SessionImplementor session)
			throws HibernateException {

		if ( !isInverse && isRowDeleteEnabled() ) {

            if (LOG.isDebugEnabled()) LOG.debugf("Deleting rows of collection: %s",
                                                 MessageHelper.collectionInfoString(this, id, getFactory()));

			boolean deleteByIndex = !isOneToMany() && hasIndex && !indexContainsFormula;
			final Expectation expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
			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;
						boolean callable = isDeleteCallable();
						boolean useBatch = expectation.canBeBatched();
						String sql = getSQLDeleteRowString();

						if ( useBatch ) {
							if ( deleteBatchKey == null ) {
								deleteBatchKey = new BasicBatchKey(
										getRole() + "#DELETE",
										expectation
								);
							}
							st = session.getTransactionCoordinator()
									.getJdbcCoordinator()
									.getBatch( deleteBatchKey )
									.getBatchStatement( sql, callable );
						}
						else {
							st = session.getTransactionCoordinator()
									.getJdbcCoordinator()
									.getStatementPreparer()
									.prepareStatement( sql, callable );
						}

						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.getTransactionCoordinator()
										.getJdbcCoordinator()
										.getBatch( deleteBatchKey )
										.addToBatch();
							}
							else {
								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
							}
							count++;
						}
						catch ( SQLException sqle ) {
							if ( useBatch ) {
								session.getTransactionCoordinator().getJdbcCoordinator().abortBatch();
							}
							throw sqle;
						}
						finally {
							if ( !useBatch ) {
								st.close();
							}
						}

                        LOG.debugf("Done deleting collection rows: %s deleted", count);
					}
                } else LOG.debugf("No rows to delete");
			}
			catch ( SQLException sqle ) {
				throw sqlExceptionHelper.convert(
				        sqle,
				        "could not delete collection rows: " +
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLDeleteRowString()
					);
			}
		}
	}

	protected boolean isRowInsertEnabled() {
		return true;
	}

	private BasicBatchKey insertBatchKey;

	public void insertRows(PersistentCollection collection, Serializable id, SessionImplementor session)
			throws HibernateException {

		if ( !isInverse && isRowInsertEnabled() ) {

            if (LOG.isDebugEnabled()) LOG.debugf("Inserting rows of collection: %s",
                                                 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 ( insertBatchKey == null ) {
								insertBatchKey = new BasicBatchKey(
										getRole() + "#INSERT",
										expectation
								);
							}
							if ( st == null ) {
								st = session.getTransactionCoordinator()
										.getJdbcCoordinator()
										.getBatch( insertBatchKey )
										.getBatchStatement( sql, callable );
							}
						}
						else {
							st = session.getTransactionCoordinator()
									.getJdbcCoordinator()
									.getStatementPreparer()
									.prepareStatement( sql, callable );
						}

						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.getTransactionCoordinator().getJdbcCoordinator().getBatch( insertBatchKey ).addToBatch();
							}
							else {
								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
							}
							collection.afterRowInsert( this, entry, i );
							count++;
						}
						catch ( SQLException sqle ) {
							if ( useBatch ) {
								session.getTransactionCoordinator().getJdbcCoordinator().abortBatch();
							}
							throw sqle;
						}
						finally {
							if ( !useBatch ) {
								st.close();
							}
						}
					}
					i++;
				}
                LOG.debugf("Done inserting rows: %s inserted", count);
			}
			catch ( SQLException sqle ) {
				throw sqlExceptionHelper.convert(
				        sqle,
				        "could not insert collection rows: " +
				        MessageHelper.collectionInfoString( this, id, getFactory() ),
				        getSQLInsertRowString()
					);
			}

		}
	}


	public String getRole() {
		return role;
	}

	public String getOwnerEntityName() {
		return entityName;
	}

	public EntityPersister getOwnerEntityPersister() {
		return ownerPersister;
	}

	public IdentifierGenerator getIdentifierGenerator() {
		return identifierGenerator;
	}

	public Type getIdentifierType() {
		return identifierType;
	}

	public boolean hasOrphanDelete() {
		return hasOrphanDelete;
	}

	public Type toType(String propertyName) throws QueryException {
		if ( "index".equals( propertyName ) ) {
			return indexType;
		}
		return elementPropertyMapping.toType( propertyName );
	}

	public abstract boolean isManyToMany();

	public String getManyToManyFilterFragment(String alias, 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();
	}

	/**
	 * {@inheritDoc}
	 */
	public String[] toColumns(String alias, String propertyName) throws QueryException {
		if ( "index".equals( propertyName ) ) {
			return qualify( alias, indexColumnNames, indexFormulaTemplates );
		}
		return elementPropertyMapping.toColumns( alias, propertyName );
	}

	private String[] indexFragments;

	/**
	 * {@inheritDoc}
	 */
	public String[] toColumns(String propertyName) throws QueryException {
		if ( "index".equals( propertyName ) ) {
			if ( indexFragments == null ) {
				String[] tmp = new String[indexColumnNames.length];
				for ( int i = 0; i < indexColumnNames.length; i++ ) {
					tmp[i] = indexColumnNames[i] == null
							? indexFormulas[i]
							: indexColumnNames[i];
					indexFragments = tmp;
				}
			}
			return indexFragments;
		}

		return elementPropertyMapping.toColumns( propertyName );
	}

	public Type getType() {
		return elementPropertyMapping.getType(); //==elementType ??
	}

	public String getName() {
		return getRole();
	}

	public EntityPersister getElementPersister() {
		if ( elementPersister == null ) {
			throw new AssertionFailure( "not an association" );
		}
		return elementPersister;
	}

	public boolean isCollection() {
		return true;
	}

	public Serializable[] getCollectionSpaces() {
		return spaces;
	}

	protected abstract String generateDeleteString();

	protected abstract String generateDeleteRowString();

	protected abstract String generateUpdateRowString();

	protected abstract String generateInsertRowString();

	public void updateRows(PersistentCollection collection, Serializable id, SessionImplementor session)
	throws HibernateException {

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

            LOG.debugf("Updating rows of collection: %s#%s", role, id);

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

            LOG.debugf("Done updating rows: %s updated", count);
		}
	}

	protected abstract int doUpdateRows(Serializable key, PersistentCollection collection, SessionImplementor session)
	throws HibernateException;

	public CollectionMetadata getCollectionMetadata() {
		return this;
	}

	public SessionFactoryImplementor getFactory() {
		return factory;
	}

	protected String filterFragment(String alias) throws MappingException {
		return hasWhere() ? " and " + getSQLWhereString( alias ) : "";
	}

	public String filterFragment(String alias, Map enabledFilters) throws MappingException {

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

		return sessionFilterFragment.append( filterFragment( alias ) ).toString();
	}

	public String oneToManyFilterFragment(String alias) throws MappingException {
		return "";
	}

	protected boolean isInsertCallable() {
		return insertCallable;
	}

	protected ExecuteUpdateResultCheckStyle getInsertCheckStyle() {
		return insertCheckStyle;
	}

	protected boolean isUpdateCallable() {
		return updateCallable;
	}

	protected ExecuteUpdateResultCheckStyle getUpdateCheckStyle() {
		return updateCheckStyle;
	}

	protected boolean isDeleteCallable() {
		return deleteCallable;
	}

	protected ExecuteUpdateResultCheckStyle getDeleteCheckStyle() {
		return deleteCheckStyle;
	}

	protected boolean isDeleteAllCallable() {
		return deleteAllCallable;
	}

	protected ExecuteUpdateResultCheckStyle getDeleteAllCheckStyle() {
		return deleteAllCheckStyle;
	}

	public String toString() {
		return StringHelper.unqualify( getClass().getName() ) + '(' + role + ')';
	}

	public boolean isVersioned() {
		return isVersioned && getOwnerEntityPersister().isVersioned();
	}

	public String getNodeName() {
		return nodeName;
	}

	public String getElementNodeName() {
		return elementNodeName;
	}

	public String getIndexNodeName() {
		return indexNodeName;
	}

	// TODO: deprecate???
	protected SQLExceptionConverter getSQLExceptionConverter() {
		return getSQLExceptionHelper().getSqlExceptionConverter();
	}

	// TODO: needed???
	protected SqlExceptionHelper getSQLExceptionHelper() {
		return sqlExceptionHelper;
	}

	public CacheEntryStructure getCacheEntryStructure() {
		return cacheEntryStructure;
	}

	public boolean isAffectedByEnabledFilters(SessionImplementor session) {
		return filterHelper.isAffectedBy( session.getEnabledFilters() ) ||
		        ( isManyToMany() && manyToManyFilterHelper.isAffectedBy( session.getEnabledFilters() ) );
	}

	public boolean isSubselectLoadable() {
		return subselectLoadable;
	}

	public boolean isMutable() {
		return isMutable;
	}

	public String[] getCollectionPropertyColumnAliases(String propertyName, 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;
	}

	//TODO: formulas ?
	public void initCollectionPropertyMap() {

		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 void initCollectionPropertyMap(String aliasName, Type type, String[] columnAliases, String[] columnNames) {

		collectionPropertyColumnAliases.put(aliasName, columnAliases);
		collectionPropertyColumnNames.put(aliasName, columnNames);

		if( type.isComponentType() ) {
			CompositeType ct = (CompositeType) 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 int getSize(Serializable key, SessionImplementor session) {
		try {
			PreparedStatement st = session.getTransactionCoordinator()
					.getJdbcCoordinator()
					.getStatementPreparer()
					.prepareStatement( 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 {
				st.close();
			}
		}
		catch (SQLException sqle) {
			throw getFactory().getSQLExceptionHelper().convert(
					sqle,
					"could not retrieve collection size: " +
					MessageHelper.collectionInfoString( this, key, getFactory() ),
					sqlSelectSizeString
				);
		}
	}

	public boolean indexExists(Serializable key, Object index, SessionImplementor session) {
		return exists(key, incrementIndexByBase(index), getIndexType(), sqlDetectRowByIndexString, session);
	}

	public boolean elementExists(Serializable key, Object element, SessionImplementor session) {
		return exists(key, element, getElementType(), sqlDetectRowByElementString, session);
	}

	private boolean exists(Serializable key, Object indexOrElement, Type indexOrElementType, String sql, SessionImplementor session) {
		try {
			PreparedStatement st = session.getTransactionCoordinator()
					.getJdbcCoordinator()
					.getStatementPreparer()
					.prepareStatement( 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 {
				st.close();
			}
		}
		catch (SQLException sqle) {
			throw getFactory().getSQLExceptionHelper().convert(
					sqle,
					"could not check row existence: " +
					MessageHelper.collectionInfoString( this, key, getFactory() ),
					sqlSelectSizeString
				);
		}
	}

	public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner) {
		try {
			PreparedStatement st = session.getTransactionCoordinator()
					.getJdbcCoordinator()
					.getStatementPreparer()
					.prepareStatement( 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 {
				st.close();
			}
		}
		catch (SQLException sqle) {
			throw getFactory().getSQLExceptionHelper().convert(
					sqle,
					"could not read row: " +
					MessageHelper.collectionInfoString( this, key, getFactory() ),
					sqlSelectSizeString
				);
		}
	}

	public boolean isExtraLazy() {
		return isExtraLazy;
	}

	protected Dialect getDialect() {
		return dialect;
	}

	/**
	 * Intended for internal use only.  In fact really only currently used from
	 * test suite for assertion purposes.
	 *
	 * @return The default collection initializer for this persister/collection.
	 */
	public CollectionInitializer getInitializer() {
		return initializer;
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate AbstractCollectionPersister.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.