FileDocCategorySizeDatePackage
AbstractEntityPersister.javaAPI DocHibernate 3.2.5128855Fri May 18 07:32:22 BST 2007org.hibernate.persister.entity

AbstractEntityPersister

public abstract class AbstractEntityPersister extends Object implements org.hibernate.metadata.ClassMetadata, org.hibernate.intercept.LazyPropertyInitializer, OuterJoinLoadable, Queryable, org.hibernate.id.PostInsertIdentityPersister, UniqueKeyLoadable, SQLLoadable, Lockable
Basic functionality for persisting an entity via JDBC through either generated or custom SQL
author
Gavin King

Fields Summary
private static final Log
log
public static final String
ENTITY_CLASS
private final org.hibernate.engine.SessionFactoryImplementor
factory
private final org.hibernate.cache.CacheConcurrencyStrategy
cache
private final boolean
isLazyPropertiesCacheable
private final org.hibernate.cache.entry.CacheEntryStructure
cacheEntryStructure
private final org.hibernate.tuple.entity.EntityMetamodel
entityMetamodel
private final Map
entityNameBySubclass
private final String[]
rootTableKeyColumnNames
private final String[]
identifierAliases
private final int
identifierColumnSpan
private final String
versionColumnName
private final boolean
hasFormulaProperties
private final int
batchSize
private final boolean
hasSubselectLoadableCollections
protected final String
rowIdName
private final Set
lazyProperties
private final String
sqlWhereString
private final String
sqlWhereStringTemplate
private final int[]
propertyColumnSpans
private final String[]
propertySubclassNames
private final String[]
propertyColumnAliases
private final String[]
propertyColumnNames
private final String[]
propertyColumnFormulaTemplates
private final boolean[]
propertyColumnUpdateable
private final boolean[]
propertyColumnInsertable
private final boolean[]
propertyUniqueness
private final boolean[]
propertySelectable
private final String[]
lazyPropertyNames
private final int[]
lazyPropertyNumbers
private final org.hibernate.type.Type[]
lazyPropertyTypes
private final String[]
lazyPropertyColumnAliases
private final String[]
subclassPropertyNameClosure
private final String[]
subclassPropertySubclassNameClosure
private final org.hibernate.type.Type[]
subclassPropertyTypeClosure
private final String[]
subclassPropertyFormulaTemplateClosure
private final String[]
subclassPropertyColumnNameClosure
private final org.hibernate.FetchMode[]
subclassPropertyFetchModeClosure
private final boolean[]
subclassPropertyNullabilityClosure
private final boolean[]
propertyDefinedOnSubclass
private final int[]
subclassPropertyColumnNumberClosure
private final int[]
subclassPropertyFormulaNumberClosure
private final org.hibernate.engine.CascadeStyle[]
subclassPropertyCascadeStyleClosure
private final String[]
subclassColumnClosure
private final boolean[]
subclassColumnLazyClosure
private final String[]
subclassColumnAliasClosure
private final boolean[]
subclassColumnSelectableClosure
private final String[]
subclassFormulaClosure
private final String[]
subclassFormulaTemplateClosure
private final String[]
subclassFormulaAliasClosure
private final boolean[]
subclassFormulaLazyClosure
private final org.hibernate.util.FilterHelper
filterHelper
private final Map
uniqueKeyLoaders
private final Map
lockers
private final Map
loaders
private String
sqlVersionSelectString
private String
sqlSnapshotSelectString
private String
sqlLazySelectString
private String
sqlIdentityInsertString
private String
sqlUpdateByRowIdString
private String
sqlLazyUpdateByRowIdString
private String[]
sqlDeleteStrings
private String[]
sqlInsertStrings
private String[]
sqlUpdateStrings
private String[]
sqlLazyUpdateStrings
private String
sqlInsertGeneratedValuesSelectString
private String
sqlUpdateGeneratedValuesSelectString
protected boolean[]
insertCallable
protected boolean[]
updateCallable
protected boolean[]
deleteCallable
protected String[]
customSQLInsert
protected String[]
customSQLUpdate
protected String[]
customSQLDelete
protected org.hibernate.engine.ExecuteUpdateResultCheckStyle[]
insertResultCheckStyles
protected org.hibernate.engine.ExecuteUpdateResultCheckStyle[]
updateResultCheckStyles
protected org.hibernate.engine.ExecuteUpdateResultCheckStyle[]
deleteResultCheckStyles
private org.hibernate.id.insert.InsertGeneratedIdentifierDelegate
identityDelegate
private boolean[]
tableHasColumns
private final String
loaderName
private org.hibernate.loader.entity.UniqueEntityLoader
queryLoader
private final String
temporaryIdTableName
private final String
temporaryIdTableDDL
private final Map
subclassPropertyAliases
private final Map
subclassPropertyColumnNames
protected final BasicEntityPropertyMapping
propertyMapping
private static final String
DISCRIMINATOR_ALIAS
Constructors Summary
public AbstractEntityPersister(org.hibernate.mapping.PersistentClass persistentClass, org.hibernate.cache.CacheConcurrencyStrategy cache, org.hibernate.engine.SessionFactoryImplementor factory)


		// moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		this.factory = factory;
		this.cache = cache;
		isLazyPropertiesCacheable = persistentClass.isLazyPropertiesCacheable();
		this.cacheEntryStructure = factory.getSettings().isStructuredCacheEntriesEnabled() ?
				(CacheEntryStructure) new StructuredCacheEntry(this) :
				(CacheEntryStructure) new UnstructuredCacheEntry();

		this.entityMetamodel = new EntityMetamodel( persistentClass, factory );

		if ( persistentClass.hasPojoRepresentation() ) {
			//TODO: this is currently specific to pojos, but need to be available for all entity-modes
			Iterator iter = persistentClass.getSubclassIterator();
			while ( iter.hasNext() ) {
				PersistentClass pc = ( PersistentClass ) iter.next();
				entityNameBySubclass.put( pc.getMappedClass(), pc.getEntityName() );
			}
		}
		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

		propertyMapping = new BasicEntityPropertyMapping( this );

		// IDENTIFIER

		identifierColumnSpan = persistentClass.getIdentifier().getColumnSpan();
		rootTableKeyColumnNames = new String[identifierColumnSpan];
		identifierAliases = new String[identifierColumnSpan];

		rowIdName = persistentClass.getRootTable().getRowId();

		loaderName = persistentClass.getLoaderName();

		Iterator iter = persistentClass.getIdentifier().getColumnIterator();
		int i = 0;
		while ( iter.hasNext() ) {
			Column col = ( Column ) iter.next();
			rootTableKeyColumnNames[i] = col.getQuotedName( factory.getDialect() );
			identifierAliases[i] = col.getAlias( factory.getDialect(), persistentClass.getRootTable() );
			i++;
		}

		// VERSION

		if ( persistentClass.isVersioned() ) {
			versionColumnName = ( ( Column ) persistentClass.getVersion().getColumnIterator().next() ).getQuotedName( factory.getDialect() );
		}
		else {
			versionColumnName = null;
		}

		//WHERE STRING

		sqlWhereString = StringHelper.isNotEmpty( persistentClass.getWhere() ) ? "( " + persistentClass.getWhere() + ") " : null;
		sqlWhereStringTemplate = sqlWhereString == null ?
				null :
				Template.renderWhereStringTemplate( sqlWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );

		// PROPERTIES

		final boolean lazyAvailable = isInstrumented(EntityMode.POJO);

		int hydrateSpan = entityMetamodel.getPropertySpan();
		propertyColumnSpans = new int[hydrateSpan];
		propertySubclassNames = new String[hydrateSpan];
		propertyColumnAliases = new String[hydrateSpan][];
		propertyColumnNames = new String[hydrateSpan][];
		propertyColumnFormulaTemplates = new String[hydrateSpan][];
		propertyUniqueness = new boolean[hydrateSpan];
		propertySelectable = new boolean[hydrateSpan];
		propertyColumnUpdateable = new boolean[hydrateSpan][];
		propertyColumnInsertable = new boolean[hydrateSpan][];
		HashSet thisClassProperties = new HashSet();

		lazyProperties = new HashSet();
		ArrayList lazyNames = new ArrayList();
		ArrayList lazyNumbers = new ArrayList();
		ArrayList lazyTypes = new ArrayList();
		ArrayList lazyColAliases = new ArrayList();

		iter = persistentClass.getPropertyClosureIterator();
		i = 0;
		boolean foundFormula = false;
		while ( iter.hasNext() ) {
			Property prop = ( Property ) iter.next();
			thisClassProperties.add( prop );

			int span = prop.getColumnSpan();
			propertyColumnSpans[i] = span;
			propertySubclassNames[i] = prop.getPersistentClass().getEntityName();
			String[] colNames = new String[span];
			String[] colAliases = new String[span];
			String[] templates = new String[span];
			Iterator colIter = prop.getColumnIterator();
			int k = 0;
			while ( colIter.hasNext() ) {
				Selectable thing = ( Selectable ) colIter.next();
				colAliases[k] = thing.getAlias( factory.getDialect() , prop.getValue().getTable() );
				if ( thing.isFormula() ) {
					foundFormula = true;
					templates[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
				}
				else {
					colNames[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
				}
				k++;
			}
			propertyColumnNames[i] = colNames;
			propertyColumnFormulaTemplates[i] = templates;
			propertyColumnAliases[i] = colAliases;

			if ( lazyAvailable && prop.isLazy() ) {
				lazyProperties.add( prop.getName() );
				lazyNames.add( prop.getName() );
				lazyNumbers.add( new Integer( i ) );
				lazyTypes.add( prop.getValue().getType() );
				lazyColAliases.add( colAliases );
			}

			propertyColumnUpdateable[i] = prop.getValue().getColumnUpdateability();
			propertyColumnInsertable[i] = prop.getValue().getColumnInsertability();

			propertySelectable[i] = prop.isSelectable();

			propertyUniqueness[i] = prop.getValue().isAlternateUniqueKey();

			i++;

		}
		hasFormulaProperties = foundFormula;
		lazyPropertyColumnAliases = ArrayHelper.to2DStringArray( lazyColAliases );
		lazyPropertyNames = ArrayHelper.toStringArray( lazyNames );
		lazyPropertyNumbers = ArrayHelper.toIntArray( lazyNumbers );
		lazyPropertyTypes = ArrayHelper.toTypeArray( lazyTypes );

		// SUBCLASS PROPERTY CLOSURE

		ArrayList columns = new ArrayList();
		ArrayList columnsLazy = new ArrayList();
		ArrayList aliases = new ArrayList();
		ArrayList formulas = new ArrayList();
		ArrayList formulaAliases = new ArrayList();
		ArrayList formulaTemplates = new ArrayList();
		ArrayList formulasLazy = new ArrayList();
		ArrayList types = new ArrayList();
		ArrayList names = new ArrayList();
		ArrayList classes = new ArrayList();
		ArrayList templates = new ArrayList();
		ArrayList propColumns = new ArrayList();
		ArrayList joinedFetchesList = new ArrayList();
		ArrayList cascades = new ArrayList();
		ArrayList definedBySubclass = new ArrayList();
		ArrayList propColumnNumbers = new ArrayList();
		ArrayList propFormulaNumbers = new ArrayList();
		ArrayList columnSelectables = new ArrayList();
		ArrayList propNullables = new ArrayList();

		iter = persistentClass.getSubclassPropertyClosureIterator();
		while ( iter.hasNext() ) {
			Property prop = ( Property ) iter.next();
			names.add( prop.getName() );
			classes.add( prop.getPersistentClass().getEntityName() );
			boolean isDefinedBySubclass = !thisClassProperties.contains( prop );
			definedBySubclass.add( Boolean.valueOf( isDefinedBySubclass ) );
			propNullables.add( Boolean.valueOf( prop.isOptional() || isDefinedBySubclass ) ); //TODO: is this completely correct?
			types.add( prop.getType() );

			Iterator colIter = prop.getColumnIterator();
			String[] cols = new String[prop.getColumnSpan()];
			String[] forms = new String[prop.getColumnSpan()];
			int[] colnos = new int[prop.getColumnSpan()];
			int[] formnos = new int[prop.getColumnSpan()];
			int l = 0;
			Boolean lazy = Boolean.valueOf( prop.isLazy() && lazyAvailable );
			while ( colIter.hasNext() ) {
				Selectable thing = ( Selectable ) colIter.next();
				if ( thing.isFormula() ) {
					String template = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
					formnos[l] = formulaTemplates.size();
					colnos[l] = -1;
					formulaTemplates.add( template );
					forms[l] = template;
					formulas.add( thing.getText( factory.getDialect() ) );
					formulaAliases.add( thing.getAlias( factory.getDialect() ) );
					formulasLazy.add( lazy );
				}
				else {
					String colName = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
					colnos[l] = columns.size(); //before add :-)
					formnos[l] = -1;
					columns.add( colName );
					cols[l] = colName;
					aliases.add( thing.getAlias( factory.getDialect(), prop.getValue().getTable() ) );
					columnsLazy.add( lazy );
					columnSelectables.add( Boolean.valueOf( prop.isSelectable() ) );
				}
				l++;
			}
			propColumns.add( cols );
			templates.add( forms );
			propColumnNumbers.add( colnos );
			propFormulaNumbers.add( formnos );

			joinedFetchesList.add( prop.getValue().getFetchMode() );
			cascades.add( prop.getCascadeStyle() );
		}
		subclassColumnClosure = ArrayHelper.toStringArray( columns );
		subclassColumnAliasClosure = ArrayHelper.toStringArray( aliases );
		subclassColumnLazyClosure = ArrayHelper.toBooleanArray( columnsLazy );
		subclassColumnSelectableClosure = ArrayHelper.toBooleanArray( columnSelectables );

		subclassFormulaClosure = ArrayHelper.toStringArray( formulas );
		subclassFormulaTemplateClosure = ArrayHelper.toStringArray( formulaTemplates );
		subclassFormulaAliasClosure = ArrayHelper.toStringArray( formulaAliases );
		subclassFormulaLazyClosure = ArrayHelper.toBooleanArray( formulasLazy );

		subclassPropertyNameClosure = ArrayHelper.toStringArray( names );
		subclassPropertySubclassNameClosure = ArrayHelper.toStringArray( classes );
		subclassPropertyTypeClosure = ArrayHelper.toTypeArray( types );
		subclassPropertyNullabilityClosure = ArrayHelper.toBooleanArray( propNullables );
		subclassPropertyFormulaTemplateClosure = ArrayHelper.to2DStringArray( templates );
		subclassPropertyColumnNameClosure = ArrayHelper.to2DStringArray( propColumns );
		subclassPropertyColumnNumberClosure = ArrayHelper.to2DIntArray( propColumnNumbers );
		subclassPropertyFormulaNumberClosure = ArrayHelper.to2DIntArray( propFormulaNumbers );

		subclassPropertyCascadeStyleClosure = new CascadeStyle[cascades.size()];
		iter = cascades.iterator();
		int j = 0;
		while ( iter.hasNext() ) {
			subclassPropertyCascadeStyleClosure[j++] = ( CascadeStyle ) iter.next();
		}
		subclassPropertyFetchModeClosure = new FetchMode[joinedFetchesList.size()];
		iter = joinedFetchesList.iterator();
		j = 0;
		while ( iter.hasNext() ) {
			subclassPropertyFetchModeClosure[j++] = ( FetchMode ) iter.next();
		}

		propertyDefinedOnSubclass = new boolean[definedBySubclass.size()];
		iter = definedBySubclass.iterator();
		j = 0;
		while ( iter.hasNext() ) {
			propertyDefinedOnSubclass[j++] = ( ( Boolean ) iter.next() ).booleanValue();
		}

		// Handle any filters applied to the class level
		filterHelper = new FilterHelper( persistentClass.getFilterMap(), factory.getDialect(), factory.getSqlFunctionRegistry() );

		temporaryIdTableName = persistentClass.getTemporaryIdTableName();
		temporaryIdTableDDL = persistentClass.getTemporaryIdTableDDL();
	
Methods Summary
protected voidaddDiscriminatorToInsert(org.hibernate.sql.Insert insert)


	    
protected voidaddDiscriminatorToSelect(org.hibernate.sql.SelectFragment select, java.lang.String name, java.lang.String suffix)

public voidafterInitialize(java.lang.Object entity, boolean lazyPropertiesAreUnfetched, org.hibernate.engine.SessionImplementor session)

		getTuplizer( session ).afterInitialize( entity, lazyPropertiesAreUnfetched, session );
	
public voidafterReassociate(java.lang.Object entity, org.hibernate.engine.SessionImplementor session)

		//if ( hasLazyProperties() ) {
		if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
			FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor( entity );
			if ( interceptor != null ) {
				interceptor.setSession( session );
			}
			else {
				FieldInterceptor fieldInterceptor = FieldInterceptionHelper.injectFieldInterceptor(
						entity,
						getEntityName(),
						null,
						session
				);
				fieldInterceptor.dirty();
			}
		}
	
public booleancanExtractIdOutOfEntity()

		return hasIdentifierProperty() || hasEmbeddedCompositeIdentifier() || hasIdentifierMapper();
	
protected booleancheck(int rows, java.io.Serializable id, int tableNumber, org.hibernate.jdbc.Expectation expectation, java.sql.PreparedStatement statement)

		try {
			expectation.verifyOutcome( rows, statement, -1 );
		}
		catch( StaleStateException e ) {
			if ( !isNullableTable( tableNumber ) ) {
				if ( getFactory().getStatistics().isStatisticsEnabled() ) {
					getFactory().getStatisticsImplementor()
							.optimisticFailure( getEntityName() );
				}
				throw new StaleObjectStateException( getEntityName(), id );
			}
		}
		catch( TooManyRowsAffectedException e ) {
			throw new HibernateException(
					"Duplicate identifier in table for: " +
					MessageHelper.infoString( this, id, getFactory() )
			);
		}
		catch ( Throwable t ) {
			return false;
		}
		return true;
	
private booleancheckVersion(boolean[] includeProperty)

        return includeProperty[ getVersionProperty() ] ||
				entityMetamodel.getPropertyUpdateGenerationInclusions()[ getVersionProperty() ] != ValueInclusion.NONE;
	
protected java.lang.StringconcretePropertySelectFragment(java.lang.String alias, org.hibernate.engine.ValueInclusion[] inclusions)

		return concretePropertySelectFragment(
				alias,
				new InclusionChecker() {
					// TODO : currently we really do not handle ValueInclusion.PARTIAL...
					// ValueInclusion.PARTIAL would indicate parts of a component need to
					// be included in the select; currently we then just render the entire
					// component into the select clause in that case.
					public boolean includeProperty(int propertyNumber) {
						return inclusions[propertyNumber] != ValueInclusion.NONE;
					}
				}
		);
	
protected java.lang.StringconcretePropertySelectFragment(java.lang.String alias, boolean[] includeProperty)

		return concretePropertySelectFragment(
				alias,
				new InclusionChecker() {
					public boolean includeProperty(int propertyNumber) {
						return includeProperty[propertyNumber];
					}
				}
		);
	
protected java.lang.StringconcretePropertySelectFragment(java.lang.String alias, org.hibernate.persister.entity.AbstractEntityPersister$InclusionChecker inclusionChecker)

		int propertyCount = getPropertyNames().length;
		int[] propertyTableNumbers = getPropertyTableNumbersInSelect();
		SelectFragment frag = new SelectFragment();
		for ( int i = 0; i < propertyCount; i++ ) {
			if ( inclusionChecker.includeProperty( i ) ) {
				frag.addColumns(
						generateTableAlias( alias, propertyTableNumbers[i] ),
						propertyColumnNames[i],
						propertyColumnAliases[i]
				);
				frag.addFormulas(
						generateTableAlias( alias, propertyTableNumbers[i] ),
						propertyColumnFormulaTemplates[i],
						propertyColumnAliases[i]
				);
			}
		}
		return frag.toFragmentString();
	
protected java.lang.StringconcretePropertySelectFragmentSansLeadingComma(java.lang.String alias, boolean[] include)

		String concretePropertySelectFragment = concretePropertySelectFragment( alias, include );
		int firstComma = concretePropertySelectFragment.indexOf( ", " );
		if ( firstComma == 0 ) {
			concretePropertySelectFragment = concretePropertySelectFragment.substring( 2 );
		}
		return concretePropertySelectFragment;
	
public booleanconsumesCollectionAlias()

		return false;
	
public booleanconsumesEntityAlias()

		return true;
	
public intcountSubclassProperties()

		return subclassPropertyTypeClosure.length;
	
protected org.hibernate.loader.entity.UniqueEntityLoadercreateEntityLoader(org.hibernate.LockMode lockMode, java.util.Map enabledFilters)

		//TODO: disable batch loading if lockMode > READ?
		return BatchingEntityLoader.createBatchingEntityLoader( this, batchSize, lockMode, getFactory(), enabledFilters );
	
protected org.hibernate.loader.entity.UniqueEntityLoadercreateEntityLoader(org.hibernate.LockMode lockMode)

		return createEntityLoader( lockMode, CollectionHelper.EMPTY_MAP );
	
protected java.lang.StringcreateFrom(int tableNumber, java.lang.String alias)

		return getSubclassTableName( tableNumber ) + ' " + alias;
	
protected org.hibernate.sql.JoinFragmentcreateJoin(java.lang.String name, boolean innerJoin, boolean includeSubclasses)

		final String[] idCols = StringHelper.qualify( name, getIdentifierColumnNames() ); //all joins join to the pk of the driving table
		final JoinFragment join = getFactory().getDialect().createOuterJoinFragment();
		final int tableSpan = getSubclassTableSpan();
		for ( int j = 1; j < tableSpan; j++ ) { //notice that we skip the first table; it is the driving table!
			final boolean joinIsIncluded = isClassOrSuperclassTable( j ) ||
					( includeSubclasses && !isSubclassTableSequentialSelect( j ) && !isSubclassTableLazy( j ) );
			if ( joinIsIncluded ) {
				join.addJoin( getSubclassTableName( j ),
						generateTableAlias( name, j ),
						idCols,
						getSubclassTableKeyColumns( j ),
						innerJoin && isClassOrSuperclassTable( j ) && !isInverseTable( j ) && !isNullableTable( j ) ?
						JoinFragment.INNER_JOIN : //we can inner join to superclass tables (the row MUST be there)
						JoinFragment.LEFT_OUTER_JOIN //we can never inner join to subclass tables
					);
			}
		}
		return join;
	
protected org.hibernate.sql.JoinFragmentcreateJoin(int[] tableNumbers, java.lang.String drivingAlias)

		final String[] keyCols = StringHelper.qualify( drivingAlias, getSubclassTableKeyColumns( tableNumbers[0] ) );
		final JoinFragment jf = getFactory().getDialect().createOuterJoinFragment();
		for ( int i = 1; i < tableNumbers.length; i++ ) { //skip the driving table
			final int j = tableNumbers[i];
			jf.addJoin( getSubclassTableName( j ),
					generateTableAlias( getRootAlias(), j ),
					keyCols,
					getSubclassTableKeyColumns( j ),
					isInverseSubclassTable( j ) || isNullableSubclassTable( j ) ?
					JoinFragment.LEFT_OUTER_JOIN :
					JoinFragment.INNER_JOIN );
		}
		return jf;
	
private voidcreateLoaders()

		loaders.put( LockMode.NONE, createEntityLoader( LockMode.NONE ) );

		UniqueEntityLoader readLoader = createEntityLoader( LockMode.READ );
		loaders.put( LockMode.READ, readLoader );

		//TODO: inexact, what we really need to know is: are any outer joins used?
		boolean disableForUpdate = getSubclassTableSpan() > 1 &&
				hasSubclasses() &&
				!getFactory().getDialect().supportsOuterJoinForUpdate();

		loaders.put(
				LockMode.UPGRADE,
				disableForUpdate ?
						readLoader :
						createEntityLoader( LockMode.UPGRADE )
			);
		loaders.put(
				LockMode.UPGRADE_NOWAIT,
				disableForUpdate ?
						readLoader :
						createEntityLoader( LockMode.UPGRADE_NOWAIT )
			);
		loaders.put(
				LockMode.FORCE,
				disableForUpdate ?
						readLoader :
						createEntityLoader( LockMode.FORCE )
			);

		loaders.put(
				"merge",
				new CascadeEntityLoader( this, CascadingAction.MERGE, getFactory() )
			);
		loaders.put(
				"refresh",
				new CascadeEntityLoader( this, CascadingAction.REFRESH, getFactory() )
			);
	
public java.lang.ObjectcreateProxy(java.io.Serializable id, org.hibernate.engine.SessionImplementor session)

		return entityMetamodel.getTuplizer( session.getEntityMode() )
				.createProxy( id, session );
	
protected voidcreateQueryLoader()

		if ( loaderName != null ) {
			queryLoader = new NamedQueryLoader( loaderName, this );
		}
	
protected org.hibernate.sql.SelectFragmentcreateSelect(int[] subclassColumnNumbers, int[] subclassFormulaNumbers)


		SelectFragment selectFragment = new SelectFragment();

		int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
		String[] columnAliases = getSubclassColumnAliasClosure();
		String[] columns = getSubclassColumnClosure();
		for ( int i = 0; i < subclassColumnNumbers.length; i++ ) {
			if ( subclassColumnSelectableClosure[i] ) {
				int columnNumber = subclassColumnNumbers[i];
				final String subalias = generateTableAlias( getRootAlias(), columnTableNumbers[columnNumber] );
				selectFragment.addColumn( subalias, columns[columnNumber], columnAliases[columnNumber] );
			}
		}

		int[] formulaTableNumbers = getSubclassFormulaTableNumberClosure();
		String[] formulaTemplates = getSubclassFormulaTemplateClosure();
		String[] formulaAliases = getSubclassFormulaAliasClosure();
		for ( int i = 0; i < subclassFormulaNumbers.length; i++ ) {
			int formulaNumber = subclassFormulaNumbers[i];
			final String subalias = generateTableAlias( getRootAlias(), formulaTableNumbers[formulaNumber] );
			selectFragment.addFormula( subalias, formulaTemplates[formulaNumber], formulaAliases[formulaNumber] );
		}

		return selectFragment;
	
private org.hibernate.loader.entity.EntityLoadercreateUniqueKeyLoader(org.hibernate.type.Type uniqueKeyType, java.lang.String[] columns, java.util.Map enabledFilters)

		if ( uniqueKeyType.isEntityType() ) {
			String className = ( ( EntityType ) uniqueKeyType ).getAssociatedEntityName();
			uniqueKeyType = getFactory().getEntityPersister( className ).getIdentifierType();
		}

		return new EntityLoader( this, columns, uniqueKeyType, 1, LockMode.NONE, getFactory(), enabledFilters );
	
protected voidcreateUniqueKeyLoaders()

		Type[] propertyTypes = getPropertyTypes();
		String[] propertyNames = getPropertyNames();
		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
			if ( propertyUniqueness[i] ) {
				//don't need filters for the static loaders
				uniqueKeyLoaders.put(
						propertyNames[i],
						createUniqueKeyLoader(
								propertyTypes[i],
								getPropertyColumnNames( i ),
								CollectionHelper.EMPTY_MAP
							)
					);
				//TODO: create uk loaders for component properties
			}
		}
	
protected java.lang.StringcreateWhereByKey(int tableNumber, java.lang.String alias)

		//TODO: move to .sql package, and refactor with similar things!
		return StringHelper.join( "=? and ",
				StringHelper.qualify( alias, getSubclassTableKeyColumns( tableNumber ) ) ) + "=?";
	
protected intdehydrate(java.io.Serializable id, java.lang.Object[] fields, boolean[] includeProperty, boolean[][] includeColumns, int j, java.sql.PreparedStatement st, org.hibernate.engine.SessionImplementor session)

		return dehydrate( id, fields, null, includeProperty, includeColumns, j, st, session, 1 );
	
protected intdehydrate(java.io.Serializable id, java.lang.Object[] fields, java.lang.Object rowId, boolean[] includeProperty, boolean[][] includeColumns, int j, java.sql.PreparedStatement ps, org.hibernate.engine.SessionImplementor session, int index)
Marshall the fields of a persistent instance to a prepared statement


		if ( log.isTraceEnabled() ) {
			log.trace( "Dehydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
		}

		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
				getPropertyTypes()[i].nullSafeSet( ps, fields[i], index, includeColumns[i], session );
				//index += getPropertyColumnSpan( i );
				index += ArrayHelper.countTrue( includeColumns[i] ); //TODO:  this is kinda slow...
			}
		}

		if ( rowId != null ) {
			ps.setObject( index, rowId );
			index += 1;
		}
		else if ( id != null ) {
			getIdentifierType().nullSafeSet( ps, id, index, session );
			index += getIdentifierColumnSpan();
		}

		return index;

	
protected voiddelete(java.io.Serializable id, java.lang.Object version, int j, java.lang.Object object, java.lang.String sql, org.hibernate.engine.SessionImplementor session, java.lang.Object[] loadedState)
Perform an SQL DELETE


		if ( isInverseTable( j ) ) {
			return;
		}

		final boolean useVersion = j == 0 && isVersioned();
		final boolean callable = isDeleteCallable( j );
		final Expectation expectation = Expectations.appropriateExpectation( deleteResultCheckStyles[j] );
		final boolean useBatch = j == 0 && isBatchable() && expectation.canBeBatched();

		if ( log.isTraceEnabled() ) {
			log.trace( "Deleting entity: " + MessageHelper.infoString( this, id, getFactory() ) );
			if ( useVersion ) {
				log.trace( "Version: " + version );
			}
		}

		if ( isTableCascadeDeleteEnabled( j ) ) {
			if ( log.isTraceEnabled() ) {
				log.trace( "delete handled by foreign key constraint: " + getTableName( j ) );
			}
			return; //EARLY EXIT!
		}

		try {

			//Render the SQL query
			PreparedStatement delete;
			int index = 1;
			if ( useBatch ) {
				if ( callable ) {
					delete = session.getBatcher().prepareBatchCallableStatement( sql );
				}
				else {
					delete = session.getBatcher().prepareBatchStatement( sql );
				}
			}
			else {
				if ( callable ) {
					delete = session.getBatcher().prepareCallableStatement( sql );
				}
				else {
					delete = session.getBatcher().prepareStatement( sql );
				}
			}

			try {

				index += expectation.prepare( delete );

				// Do the key. The key is immutable so we can use the _current_ object state - not necessarily
				// the state at the time the delete was issued
				getIdentifierType().nullSafeSet( delete, id, index, session );
				index += getIdentifierColumnSpan();

				// We should use the _current_ object state (ie. after any updates that occurred during flush)

				if ( useVersion ) {
					getVersionType().nullSafeSet( delete, version, index, session );
				}
				else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && loadedState != null ) {
					boolean[] versionability = getPropertyVersionability();
					Type[] types = getPropertyTypes();
					for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
						if ( isPropertyOfTable( i, j ) && versionability[i] ) {
							// this property belongs to the table and it is not specifically
							// excluded from optimistic locking by optimistic-lock="false"
							boolean[] settable = types[i].toColumnNullness( loadedState[i], getFactory() );
							types[i].nullSafeSet( delete, loadedState[i], index, settable, session );
							index += ArrayHelper.countTrue( settable );
						}
					}
				}

				if ( useBatch ) {
					session.getBatcher().addToBatch( expectation );
				}
				else {
					check( delete.executeUpdate(), id, j, expectation, delete );
				}

			}
			catch ( SQLException sqle ) {
				if ( useBatch ) {
					session.getBatcher().abortBatch( sqle );
				}
				throw sqle;
			}
			finally {
				if ( !useBatch ) {
					session.getBatcher().closeStatement( delete );
				}
			}

		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not delete: " +
					MessageHelper.infoString( this, id, getFactory() ),
					sql
				);

		}

	
public voiddelete(java.io.Serializable id, java.lang.Object version, java.lang.Object object, org.hibernate.engine.SessionImplementor session)
Delete an object

		final int span = getTableSpan();
		boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned() && entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION;
		Object[] loadedState = null;
		if ( isImpliedOptimisticLocking ) {
			// need to treat this as if it where optimistic-lock="all" (dirty does *not* make sense);
			// first we need to locate the "loaded" state
			//
			// Note, it potentially could be a proxy, so perform the location the safe way...
			EntityKey key = new EntityKey( id, this, session.getEntityMode() );
			Object entity = session.getPersistenceContext().getEntity( key );
			if ( entity != null ) {
				EntityEntry entry = session.getPersistenceContext().getEntry( entity );
				loadedState = entry.getLoadedState();
			}
		}

		final String[] deleteStrings;
		if ( isImpliedOptimisticLocking && loadedState != null ) {
			// we need to utilize dynamic delete statements
			deleteStrings = generateSQLDeletStrings( loadedState );
		}
		else {
			// otherwise, utilize the static delete statements
			deleteStrings = getSQLDeleteStrings();
		}

		for ( int j = span - 1; j >= 0; j-- ) {
			delete( id, version, j, object, deleteStrings[j], session, loadedState );
		}

	
public java.lang.StringfilterFragment(java.lang.String alias, java.util.Map enabledFilters)

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

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

public int[]findDirty(java.lang.Object[] currentState, java.lang.Object[] previousState, java.lang.Object entity, org.hibernate.engine.SessionImplementor session)
Locate the property-indices of all properties considered to be dirty.

param
currentState The current state of the entity (the state to be checked).
param
previousState The previous state of the entity (the state to be checked against).
param
entity The entity for which we are checking state dirtiness.
param
session The session in which the check is ccurring.
return
null or the indices of the dirty properties
throws
HibernateException

		int[] props = TypeFactory.findDirty(
				entityMetamodel.getProperties(),
				currentState,
				previousState,
				propertyColumnUpdateable,
				hasUninitializedLazyProperties( entity, session.getEntityMode() ),
				session
			);
		if ( props == null ) {
			return null;
		}
		else {
			logDirtyProperties( props );
			return props;
		}
	
public int[]findModified(java.lang.Object[] old, java.lang.Object[] current, java.lang.Object entity, org.hibernate.engine.SessionImplementor session)
Locate the property-indices of all properties considered to be dirty.

param
old The old state of the entity.
param
current The current state of the entity.
param
entity The entity for which we are checking state modification.
param
session The session in which the check is ccurring.
return
null or the indices of the modified properties
throws
HibernateException

		int[] props = TypeFactory.findModified(
				entityMetamodel.getProperties(),
				current,
				old,
				propertyColumnUpdateable,
				hasUninitializedLazyProperties( entity, session.getEntityMode() ),
				session
			);
		if ( props == null ) {
			return null;
		}
		else {
			logDirtyProperties( props );
			return props;
		}
	
public java.lang.ObjectforceVersionIncrement(java.io.Serializable id, java.lang.Object currentVersion, org.hibernate.engine.SessionImplementor session)

		if ( !isVersioned() ) {
			throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
		}

		if ( isVersionPropertyGenerated() ) {
			// the difficulty here is exactly what do we update in order to
			// force the version to be incremented in the db...
			throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
		}

		Object nextVersion = getVersionType().next( currentVersion, session );
		if ( log.isTraceEnabled() ) {
			log.trace(
					"Forcing version increment [" + MessageHelper.infoString( this, id, getFactory() ) +
					"; " + getVersionType().toLoggableString( currentVersion, getFactory() ) +
					" -> " + getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
			);
		}

		// todo : cache this sql...
		String versionIncrementString = generateVersionIncrementUpdateString();
		PreparedStatement st = null;
		try {
			try {
				st = session.getBatcher().prepareStatement( versionIncrementString );
				getVersionType().nullSafeSet( st, nextVersion, 1, session );
				getIdentifierType().nullSafeSet( st, id, 2, session );
				getVersionType().nullSafeSet( st, currentVersion, 2 + getIdentifierColumnSpan(), session );
				int rows = st.executeUpdate();
				if ( rows != 1 ) {
					throw new StaleObjectStateException( getEntityName(), id );
				}
			}
			finally {
				session.getBatcher().closeStatement( st );
			}
		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not retrieve version: " +
					MessageHelper.infoString( this, id, getFactory() ),
					getVersionSelectString()
				);
		}

		return nextVersion;
	
public java.lang.StringfromJoinFragment(java.lang.String alias, boolean innerJoin, boolean includeSubclasses)

		return getSubclassTableSpan() == 1 ?
				"" : //just a performance opt!
				createJoin( alias, innerJoin, includeSubclasses ).toFromFragmentString();
	
protected java.lang.StringgenerateDeleteString(int j)
Generate the SQL that deletes a row by id (and version)

		Delete delete = new Delete()
				.setTableName( getTableName( j ) )
				.setPrimaryKeyColumnNames( getKeyColumns( j ) );
		if ( j == 0 ) {
			delete.setVersionColumnName( getVersionColumnName() );
		}
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			delete.setComment( "delete " + getEntityName() );
		}
		return delete.toStatementString();
	
public java.lang.StringgenerateFilterConditionAlias(java.lang.String rootAlias)

		return rootAlias;
	
private java.lang.StringgenerateGeneratedValuesSelectString(org.hibernate.engine.ValueInclusion[] inclusions)

		Select select = new Select( getFactory().getDialect() );

		if ( getFactory().getSettings().isCommentsEnabled() ) {
			select.setComment( "get generated state " + getEntityName() );
		}

		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );

		// Here we render the select column list based on the properties defined as being generated.
		// For partial component generation, we currently just re-select the whole component
		// rather than trying to handle the individual generated portions.
		String selectClause = concretePropertySelectFragment( getRootAlias(), inclusions );
		selectClause = selectClause.substring( 2 );

		String fromClause = fromTableFragment( getRootAlias() ) +
				fromJoinFragment( getRootAlias(), true, false );

		String whereClause = new StringBuffer()
			.append( StringHelper.join( "=? and ", aliasedIdColumns ) )
			.append( "=?" )
			.append( whereJoinFragment( getRootAlias(), true, false ) )
			.toString();

		return select.setSelectClause( selectClause )
				.setFromClause( fromClause )
				.setOuterJoins( "", "" )
				.setWhereClause( whereClause )
				.toStatementString();
	
protected java.lang.StringgenerateIdentityInsertString(boolean[] includeProperty)
Used to generate an insery statement against the root table in the case of identifier generation strategies where the insert statement executions actually generates the identifier value.

param
includeProperty indices of the properties to include in the insert statement.
return
The insert SQL statement string

		Insert insert = identityDelegate.prepareIdentifierGeneratingInsert();
		insert.setTableName( getTableName( 0 ) );

		// add normal properties
		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
			if ( includeProperty[i] && isPropertyOfTable( i, 0 ) ) {
				// this property belongs on the table and is to be inserted
				insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
			}
		}

		// add the discriminator
		addDiscriminatorToInsert( insert );

		// delegate already handles PK columns

		if ( getFactory().getSettings().isCommentsEnabled() ) {
			insert.setComment( "insert " + getEntityName() );
		}

		return insert.toStatementString();
	
protected java.lang.StringgenerateInsertGeneratedValuesSelectString()

		return generateGeneratedValuesSelectString( getPropertyInsertGenerationInclusions() );
	
protected java.lang.StringgenerateInsertString(boolean[] includeProperty, int j)

		return generateInsertString( false, includeProperty, j );
	
protected java.lang.StringgenerateInsertString(boolean identityInsert, boolean[] includeProperty)

		return generateInsertString( identityInsert, includeProperty, 0 );
	
protected java.lang.StringgenerateInsertString(boolean identityInsert, boolean[] includeProperty, int j)
Generate the SQL that inserts a row


		// todo : remove the identityInsert param and variations;
		//   identity-insert strings are now generated from generateIdentityInsertString()

		Insert insert = new Insert( getFactory().getDialect() )
				.setTableName( getTableName( j ) );

		// add normal properties
		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
				// this property belongs on the table and is to be inserted
				insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
			}
		}

		// add the discriminator
		if ( j == 0 ) {
			addDiscriminatorToInsert( insert );
		}

		// add the primary key
		if ( j == 0 && identityInsert ) {
			insert.addIdentityColumn( getKeyColumns( 0 )[0] );
		}
		else {
			insert.addColumns( getKeyColumns( j ) );
		}

		if ( getFactory().getSettings().isCommentsEnabled() ) {
			insert.setComment( "insert " + getEntityName() );
		}

		String result = insert.toStatementString();

		// append the SQL to return the generated identifier
		if ( j == 0 && identityInsert && useInsertSelectIdentity() ) { //TODO: suck into Insert
			result = getFactory().getDialect().appendIdentitySelectToInsert( result );
		}

		return result;
	
protected java.lang.StringgenerateLazySelectString()


		if ( !entityMetamodel.hasLazyProperties() ) {
			return null;
		}

		HashSet tableNumbers = new HashSet();
		ArrayList columnNumbers = new ArrayList();
		ArrayList formulaNumbers = new ArrayList();
		for ( int i = 0; i < lazyPropertyNames.length; i++ ) {
			// all this only really needs to consider properties
			// of this class, not its subclasses, but since we
			// are reusing code used for sequential selects, we
			// use the subclass closure
			int propertyNumber = getSubclassPropertyIndex( lazyPropertyNames[i] );

			int tableNumber = getSubclassPropertyTableNumber( propertyNumber );
			tableNumbers.add( new Integer( tableNumber ) );

			int[] colNumbers = subclassPropertyColumnNumberClosure[propertyNumber];
			for ( int j = 0; j < colNumbers.length; j++ ) {
				if ( colNumbers[j]!=-1 ) {
					columnNumbers.add( new Integer( colNumbers[j] ) );
				}
			}
			int[] formNumbers = subclassPropertyFormulaNumberClosure[propertyNumber];
			for ( int j = 0; j < formNumbers.length; j++ ) {
				if ( formNumbers[j]!=-1 ) {
					formulaNumbers.add( new Integer( formNumbers[j] ) );
				}
			}
		}

		if ( columnNumbers.size()==0 && formulaNumbers.size()==0 ) {
			// only one-to-one is lazy fetched
			return null;
		}

		return renderSelect( ArrayHelper.toIntArray( tableNumbers ),
				ArrayHelper.toIntArray( columnNumbers ),
				ArrayHelper.toIntArray( formulaNumbers ) );

	
protected org.hibernate.dialect.lock.LockingStrategygenerateLocker(org.hibernate.LockMode lockMode)

		return factory.getDialect().getLockingStrategy( this, lockMode );
	
private java.lang.String[]generateSQLDeletStrings(java.lang.Object[] loadedState)

		int span = getTableSpan();
		String[] deleteStrings = new String[span];
		for ( int j = span - 1; j >= 0; j-- ) {
			Delete delete = new Delete()
					.setTableName( getTableName( j ) )
					.setPrimaryKeyColumnNames( getKeyColumns( j ) );
			if ( getFactory().getSettings().isCommentsEnabled() ) {
				delete.setComment( "delete " + getEntityName() + " [" + j + "]" );
			}

			boolean[] versionability = getPropertyVersionability();
			Type[] types = getPropertyTypes();
			for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
				if ( isPropertyOfTable( i, j ) && versionability[i] ) {
					// this property belongs to the table and it is not specifically
					// excluded from optimistic locking by optimistic-lock="false"
					String[] propertyColumnNames = getPropertyColumnNames( i );
					boolean[] propertyNullness = types[i].toColumnNullness( loadedState[i], getFactory() );
					for ( int k = 0; k < propertyNullness.length; k++ ) {
						if ( propertyNullness[k] ) {
							delete.addWhereFragment( propertyColumnNames[k] + " = ?" );
						}
						else {
							delete.addWhereFragment( propertyColumnNames[k] + " is null" );
						}
					}
				}
			}
			deleteStrings[j] = delete.toStatementString();
		}
		return deleteStrings;
	
protected java.lang.StringgenerateSelectVersionString()
Generate the SQL that selects the version number by id

		SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
				.setTableName( getVersionedTableName() );
		if ( isVersioned() ) {
			select.addColumn( versionColumnName );
		}
		else {
			select.addColumns( rootTableKeyColumnNames );
		}
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			select.setComment( "get version " + getEntityName() );
		}
		return select.addCondition( rootTableKeyColumnNames, "=?" ).toStatementString();
	
protected java.lang.StringgenerateSnapshotSelectString()


		//TODO: should we use SELECT .. FOR UPDATE?

		Select select = new Select( getFactory().getDialect() );

		if ( getFactory().getSettings().isCommentsEnabled() ) {
			select.setComment( "get current state " + getEntityName() );
		}

		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
		String selectClause = StringHelper.join( ", ", aliasedIdColumns ) +
				concretePropertySelectFragment( getRootAlias(), getPropertyUpdateability() );

		String fromClause = fromTableFragment( getRootAlias() ) +
				fromJoinFragment( getRootAlias(), true, false );

		String whereClause = new StringBuffer()
			.append( StringHelper.join( "=? and ",
					aliasedIdColumns ) )
			.append( "=?" )
			.append( whereJoinFragment( getRootAlias(), true, false ) )
			.toString();

		/*if ( isVersioned() ) {
			where.append(" and ")
				.append( getVersionColumnName() )
				.append("=?");
		}*/

		return select.setSelectClause( selectClause )
				.setFromClause( fromClause )
				.setOuterJoins( "", "" )
				.setWhereClause( whereClause )
				.toStatementString();
	
protected java.lang.StringgenerateTableAlias(java.lang.String rootAlias, int tableNumber)

		if ( tableNumber == 0 ) {
			return rootAlias;
		}
		StringBuffer buf = new StringBuffer().append( rootAlias );
		if ( !rootAlias.endsWith( "_" ) ) {
			buf.append( '_" );
		}
		return buf.append( tableNumber ).append( '_" ).toString();
	
protected java.lang.StringgenerateUpdateGeneratedValuesSelectString()

		return generateGeneratedValuesSelectString( getPropertyUpdateGenerationInclusions() );
	
protected java.lang.StringgenerateUpdateString(boolean[] includeProperty, int j, boolean useRowId)

		return generateUpdateString( includeProperty, j, null, useRowId );
	
protected java.lang.StringgenerateUpdateString(boolean[] includeProperty, int j, java.lang.Object[] oldFields, boolean useRowId)
Generate the SQL that updates a row by id (and version)


		Update update = new Update( getFactory().getDialect() ).setTableName( getTableName( j ) );

		// select the correct row by either pk or rowid
		if ( useRowId ) {
			update.setPrimaryKeyColumnNames( new String[]{rowIdName} ); //TODO: eventually, rowIdName[j]
		}
		else {
			update.setPrimaryKeyColumnNames( getKeyColumns( j ) );
		}

		boolean hasColumns = false;
		for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
				// this is a property of the table, which we are updating
				update.addColumns( getPropertyColumnNames(i), propertyColumnUpdateable[i] );
				hasColumns = hasColumns || getPropertyColumnSpan( i ) > 0;
			}
		}

		if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_VERSION ) {
			// this is the root (versioned) table, and we are using version-based
			// optimistic locking;  if we are not updating the version, also don't
			// check it (unless this is a "generated" version column)!
			if ( checkVersion( includeProperty ) ) {
				update.setVersionColumnName( getVersionColumnName() );
				hasColumns = true;
			}
		}
		else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
			// we are using "all" or "dirty" property-based optimistic locking

			boolean[] includeInWhere = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
					getPropertyUpdateability() : //optimistic-lock="all", include all updatable properties
					includeProperty; //optimistic-lock="dirty", include all properties we are updating this time

			boolean[] versionability = getPropertyVersionability();
			Type[] types = getPropertyTypes();
			for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
				boolean include = includeInWhere[i] &&
						isPropertyOfTable( i, j ) &&
						versionability[i];
				if ( include ) {
					// this property belongs to the table, and it is not specifically
					// excluded from optimistic locking by optimistic-lock="false"
					String[] propertyColumnNames = getPropertyColumnNames( i );
					boolean[] propertyNullness = types[i].toColumnNullness( oldFields[i], getFactory() );
					for ( int k=0; k<propertyNullness.length; k++ ) {
						if ( propertyNullness[k] ) {
							update.addWhereColumn( propertyColumnNames[k] );
						}
						else {
							update.addWhereColumn( propertyColumnNames[k], " is null" );
						}
					}
				}
			}

		}

		if ( getFactory().getSettings().isCommentsEnabled() ) {
			update.setComment( "update " + getEntityName() );
		}

		return hasColumns ? update.toStatementString() : null;
	
private java.lang.StringgenerateVersionIncrementUpdateString()

		Update update = new Update( getFactory().getDialect() );
		update.setTableName( getTableName( 0 ) );
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			update.setComment( "forced version increment" );
		}
		update.addColumn( getVersionColumnName() );
		update.setPrimaryKeyColumnNames( getIdentifierColumnNames() );
		update.setVersionColumnName( getVersionColumnName() );
		return update.toStatementString();
	
private org.hibernate.loader.entity.UniqueEntityLoadergetAppropriateLoader(org.hibernate.LockMode lockMode, org.hibernate.engine.SessionImplementor session)

		final Map enabledFilters = session.getEnabledFilters();
		if ( queryLoader != null ) {
			return queryLoader;
		}
		else if ( enabledFilters == null || enabledFilters.isEmpty() ) {
			if ( session.getFetchProfile()!=null && LockMode.UPGRADE.greaterThan(lockMode) ) {
				return (UniqueEntityLoader) loaders.get( session.getFetchProfile() );
			}
			else {
				return (UniqueEntityLoader) loaders.get( lockMode );
			}
		}
		else {
			return createEntityLoader( lockMode, enabledFilters );
		}
	
private org.hibernate.loader.entity.EntityLoadergetAppropriateUniqueKeyLoader(java.lang.String propertyName, java.util.Map enabledFilters)


		final boolean useStaticLoader = ( enabledFilters == null || enabledFilters.isEmpty() )
				&& propertyName.indexOf('.")<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties

		if ( useStaticLoader ) {
			return (EntityLoader) uniqueKeyLoaders.get( propertyName );
		}
		else {
			return createUniqueKeyLoader(
					propertyMapping.toType(propertyName),
					propertyMapping.toColumns(propertyName),
					enabledFilters
				);
		}
	
public org.hibernate.cache.CacheConcurrencyStrategygetCache()

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

		return cacheEntryStructure;
	
public org.hibernate.engine.CascadeStylegetCascadeStyle(int i)

		return subclassPropertyCascadeStyleClosure[i];
	
public org.hibernate.metadata.ClassMetadatagetClassMetadata()

		return this;
	
public java.lang.ClassgetConcreteProxyClass(org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).getConcreteProxyClass();
	
public java.lang.ObjectgetCurrentVersion(java.io.Serializable id, org.hibernate.engine.SessionImplementor session)
Retrieve the version number


		if ( log.isTraceEnabled() ) {
			log.trace( "Getting version: " + MessageHelper.infoString( this, id, getFactory() ) );
		}

		try {

			PreparedStatement st = session.getBatcher().prepareSelectStatement( getVersionSelectString() );
			try {
				getIdentifierType().nullSafeSet( st, id, 1, session );

				ResultSet rs = st.executeQuery();
				try {
					if ( !rs.next() ) {
						return null;
					}
					if ( !isVersioned() ) {
						return this;
					}
					return getVersionType().nullSafeGet( rs, getVersionColumnName(), session, null );
				}
				finally {
					rs.close();
				}
			}
			finally {
				session.getBatcher().closeStatement( st );
			}

		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not retrieve version: " +
					MessageHelper.infoString( this, id, getFactory() ),
					getVersionSelectString()
				);
		}

	
public java.lang.Object[]getDatabaseSnapshot(java.io.Serializable id, org.hibernate.engine.SessionImplementor session)


		if ( log.isTraceEnabled() ) {
			log.trace( "Getting current persistent state for: " + MessageHelper.infoString( this, id, getFactory() ) );
		}

		try {
			PreparedStatement ps = session.getBatcher().prepareSelectStatement( getSQLSnapshotSelectString() );
			try {
				getIdentifierType().nullSafeSet( ps, id, 1, session );
				//if ( isVersioned() ) getVersionType().nullSafeSet( ps, version, getIdentifierColumnSpan()+1, session );
				ResultSet rs = ps.executeQuery();
				try {
					//if there is no resulting row, return null
					if ( !rs.next() ) {
						return null;
					}

					//otherwise return the "hydrated" state (ie. associations are not resolved)
					Type[] types = getPropertyTypes();
					Object[] values = new Object[types.length];
					boolean[] includeProperty = getPropertyUpdateability();
					for ( int i = 0; i < types.length; i++ ) {
						if ( includeProperty[i] ) {
							values[i] = types[i].hydrate( rs, getPropertyAliases( "", i ), session, null ); //null owner ok??
						}
					}
					return values;
				}
				finally {
					rs.close();
				}
			}
			finally {
				session.getBatcher().closeStatement( ps );
			}
		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not retrieve snapshot: " +
					MessageHelper.infoString( this, id, getFactory() ),
			        getSQLSnapshotSelectString()
				);
		}

	
protected java.lang.StringgetDiscriminatorAlias()

		return DISCRIMINATOR_ALIAS;
	
public java.lang.StringgetDiscriminatorAlias(java.lang.String suffix)

		// NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
		// was toUnqotedAliasStrings( getdiscriminatorColumnName() ) before - now tried
		// to remove that unqoting and missing aliases..
		return entityMetamodel.hasSubclasses() ?
				new Alias( suffix ).toAliasString( getDiscriminatorAlias() ) :
				null;
	
public java.lang.StringgetDiscriminatorColumnName()


	   
		return DISCRIMINATOR_ALIAS;
	
protected java.lang.StringgetDiscriminatorFormulaTemplate()

		return null;
	
public org.hibernate.tuple.entity.EntityMetamodelgetEntityMetamodel()

		return entityMetamodel;
	
public final java.lang.StringgetEntityName()

		return entityMetamodel.getName();
	
public org.hibernate.type.EntityTypegetEntityType()

		return entityMetamodel.getEntityType();
	
public org.hibernate.engine.SessionFactoryImplementorgetFactory()

		return factory;
	
public org.hibernate.FetchModegetFetchMode(int i)

		return subclassPropertyFetchModeClosure[i];
	
public java.io.SerializablegetIdentifier(java.lang.Object object, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).getIdentifier( object );
	
protected java.lang.String[]getIdentifierAliases()

		return identifierAliases;
	
public java.lang.String[]getIdentifierAliases(java.lang.String suffix)

		// NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
		// was toUnqotedAliasStrings( getIdentiferColumnNames() ) before - now tried
		// to remove that unqoting and missing aliases..
		return new Alias( suffix ).toAliasStrings( getIdentifierAliases() );
	
public java.lang.String[]getIdentifierColumnNames()

		return rootTableKeyColumnNames;
	
protected intgetIdentifierColumnSpan()

		return identifierColumnSpan;
	
public org.hibernate.id.IdentifierGeneratorgetIdentifierGenerator()

		return entityMetamodel.getIdentifierProperty().getIdentifierGenerator();
	
public java.lang.StringgetIdentifierPropertyName()

		return entityMetamodel.getIdentifierProperty().getName();
	
public org.hibernate.type.TypegetIdentifierType()

		return entityMetamodel.getIdentifierProperty().getType();
	
public java.lang.StringgetIdentitySelectString()

		//TODO: cache this in an instvar
		return getFactory().getDialect().getIdentitySelectString(
				getTableName(0),
				getKeyColumns(0)[0],
				getIdentifierType().sqlTypes( getFactory() )[0]
		);
	
public java.lang.String[]getKeyColumnNames()

		return getIdentifierColumnNames();
	
protected abstract java.lang.String[]getKeyColumns(int j)

protected java.util.SetgetLazyProperties()

		return lazyProperties;
	
private org.hibernate.dialect.lock.LockingStrategygetLocker(org.hibernate.LockMode lockMode)

		return ( LockingStrategy ) lockers.get( lockMode );
	
public final java.lang.ClassgetMappedClass(org.hibernate.EntityMode entityMode)

		Tuplizer tup = entityMetamodel.getTuplizerOrNull(entityMode);
		return tup==null ? null : tup.getMappedClass();
	
public java.lang.StringgetMappedSuperclass()

		return entityMetamodel.getSuperclass();
	
public java.lang.StringgetName()

		return getEntityName();
	
public int[]getNaturalIdentifierProperties()

		return entityMetamodel.getNaturalIdentifierProperties();
	
public java.lang.Object[]getNaturalIdentifierSnapshot(java.io.Serializable id, org.hibernate.engine.SessionImplementor session)

		if ( !hasNaturalIdentifier() ) {
			throw new MappingException( "persistent class did not define a natural-id : " + MessageHelper.infoString( this ) );
		}
		if ( log.isTraceEnabled() ) {
			log.trace( "Getting current natural-id snapshot state for: " + MessageHelper.infoString( this, id, getFactory() ) );
		}

		int[] naturalIdPropertyIndexes = getNaturalIdentifierProperties();
		int naturalIdPropertyCount = naturalIdPropertyIndexes.length;
		boolean[] naturalIdMarkers = new boolean[ getPropertySpan() ];
		Type[] extractionTypes = new Type[ naturalIdPropertyCount ];
		for ( int i = 0; i < naturalIdPropertyCount; i++ ) {
			extractionTypes[i] = getPropertyTypes()[ naturalIdPropertyIndexes[i] ];
			naturalIdMarkers[ naturalIdPropertyIndexes[i] ] = true;
		}

		///////////////////////////////////////////////////////////////////////
		// TODO : look at perhaps caching this...
		Select select = new Select( getFactory().getDialect() );
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			select.setComment( "get current natural-id state " + getEntityName() );
		}
		select.setSelectClause( concretePropertySelectFragmentSansLeadingComma( getRootAlias(), naturalIdMarkers ) );
		select.setFromClause( fromTableFragment( getRootAlias() ) + fromJoinFragment( getRootAlias(), true, false ) );

		String[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
		String whereClause = new StringBuffer()
			.append( StringHelper.join( "=? and ",
					aliasedIdColumns ) )
			.append( "=?" )
			.append( whereJoinFragment( getRootAlias(), true, false ) )
			.toString();

		String sql = select.setOuterJoins( "", "" )
				.setWhereClause( whereClause )
				.toStatementString();
		///////////////////////////////////////////////////////////////////////

		Object[] snapshot = new Object[ naturalIdPropertyCount ];
		try {
			PreparedStatement ps = session.getBatcher().prepareSelectStatement( sql );
			try {
				getIdentifierType().nullSafeSet( ps, id, 1, session );
				ResultSet rs = ps.executeQuery();
				try {
					//if there is no resulting row, return null
					if ( !rs.next() ) {
						return null;
					}

					for ( int i = 0; i < naturalIdPropertyCount; i++ ) {
						snapshot[i] = extractionTypes[i].hydrate( rs, getPropertyAliases( "", naturalIdPropertyIndexes[i] ), session, null );
					}
					return snapshot;
				}
				finally {
					rs.close();
				}
			}
			finally {
				session.getBatcher().closeStatement( ps );
			}
		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not retrieve snapshot: " +
					MessageHelper.infoString( this, id, getFactory() ),
			        sql
				);
		}
	
public boolean[]getNonLazyPropertyUpdateability()

		return entityMetamodel.getNonlazyPropertyUpdateability();
	
protected boolean[]getPropertiesToInsert(java.lang.Object[] fields)
Transform the array of property indexes to an array of booleans, true when the property is insertable and non-null

		boolean[] notNull = new boolean[fields.length];
		boolean[] insertable = getPropertyInsertability();
		for ( int i = 0; i < fields.length; i++ ) {
			notNull[i] = insertable[i] && fields[i] != null;
		}
		return notNull;
	
protected final boolean[]getPropertiesToUpdate(int[] dirtyProperties, boolean hasDirtyCollection)
Transform the array of property indexes to an array of booleans, true when the property is dirty

		final boolean[] propsToUpdate = new boolean[ entityMetamodel.getPropertySpan() ];
		final boolean[] updateability = getPropertyUpdateability(); //no need to check laziness, dirty checking handles that
		for ( int j = 0; j < dirtyProperties.length; j++ ) {
			int property = dirtyProperties[j];
			if ( updateability[property] ) {
				propsToUpdate[property] = true;
			}
		}
		if ( isVersioned() ) {
			propsToUpdate[ getVersionProperty() ] =
				Versioning.isVersionIncrementRequired( dirtyProperties, hasDirtyCollection, getPropertyVersionability() );
		}
		return propsToUpdate;
	
public java.lang.String[]getPropertyAliases(java.lang.String suffix, int i)

		// NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
		return new Alias( suffix ).toUnquotedAliasStrings( propertyColumnAliases[i] );
	
public org.hibernate.engine.CascadeStyle[]getPropertyCascadeStyles()

		return entityMetamodel.getCascadeStyles();
	
public boolean[]getPropertyCheckability()

		return entityMetamodel.getPropertyCheckability();
	
public java.lang.String[]getPropertyColumnNames(int i)

		return propertyColumnNames[i];
	
public java.lang.String[]getPropertyColumnNames(java.lang.String propertyName)

		return propertyMapping.getColumnNames( propertyName );
	
protected intgetPropertyColumnSpan(int i)

		return propertyColumnSpans[i];
	
public intgetPropertyIndex(java.lang.String propertyName)

		return entityMetamodel.getPropertyIndex(propertyName);
	
public org.hibernate.engine.ValueInclusion[]getPropertyInsertGenerationInclusions()

		return entityMetamodel.getPropertyInsertGenerationInclusions();
	
public boolean[]getPropertyInsertability()

		return entityMetamodel.getPropertyInsertability();
	
public boolean[]getPropertyLaziness()

		return entityMetamodel.getPropertyLaziness();
	
public java.lang.String[]getPropertyNames()

		return entityMetamodel.getPropertyNames();
	
public boolean[]getPropertyNullability()

		return entityMetamodel.getPropertyNullability();
	
protected intgetPropertySpan()

		return entityMetamodel.getPropertySpan();
	
protected java.lang.String[]getPropertySubclassNames()

		return propertySubclassNames;
	
protected abstract int[]getPropertyTableNumbers()

protected abstract int[]getPropertyTableNumbersInSelect()

public org.hibernate.type.TypegetPropertyType(java.lang.String propertyName)

		return propertyMapping.toType(propertyName);
	
public org.hibernate.type.Type[]getPropertyTypes()

		return entityMetamodel.getPropertyTypes();
	
public org.hibernate.engine.ValueInclusion[]getPropertyUpdateGenerationInclusions()

		return entityMetamodel.getPropertyUpdateGenerationInclusions();
	
protected boolean[]getPropertyUpdateability(java.lang.Object entity, org.hibernate.EntityMode entityMode)
Which properties appear in the SQL update? (Initialized, updateable ones!)

		return hasUninitializedLazyProperties( entity, entityMode ) ?
				getNonLazyPropertyUpdateability() :
				getPropertyUpdateability();
	
public boolean[]getPropertyUpdateability()

		return entityMetamodel.getPropertyUpdateability();
	
public java.lang.ObjectgetPropertyValue(java.lang.Object object, int i, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).getPropertyValue( object , i );
	
public java.lang.ObjectgetPropertyValue(java.lang.Object object, java.lang.String propertyName, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).getPropertyValue( object, propertyName );
	
public java.lang.Object[]getPropertyValues(java.lang.Object object, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).getPropertyValues( object );
	
public java.lang.Object[]getPropertyValuesToInsert(java.lang.Object object, java.util.Map mergeMap, org.hibernate.engine.SessionImplementor session)

		return getTuplizer( session.getEntityMode() ).getPropertyValuesToInsert( object, mergeMap, session );
	
public boolean[]getPropertyVersionability()

		return entityMetamodel.getPropertyVersionability();
	
public java.io.Serializable[]getQuerySpaces()

		return getPropertySpaces();
	
private java.lang.StringgetRootAlias()

		return StringHelper.generateAlias( getEntityName() );
	
public java.lang.StringgetRootEntityName()

		return entityMetamodel.getRootName();
	
public java.lang.StringgetRootTableAlias(java.lang.String drivingAlias)

		return drivingAlias;
	
public java.lang.String[]getRootTableIdentifierColumnNames()

		return getRootTableKeyColumnNames();
	
public java.lang.String[]getRootTableKeyColumnNames()

		return rootTableKeyColumnNames;
	
public java.lang.StringgetRootTableName()

		return getSubclassTableName( 0 );
	
protected java.lang.String[]getSQLDeleteStrings()

		return sqlDeleteStrings;
	
protected java.lang.StringgetSQLIdentityInsertString()
The query that inserts a row, letting the database generate an id

return
The IDENTITY-based insertion query.

		return sqlIdentityInsertString;
	
protected java.lang.String[]getSQLInsertStrings()

		return sqlInsertStrings;
	
protected java.lang.StringgetSQLLazySelectString()

		return sqlLazySelectString;
	
protected java.lang.String[]getSQLLazyUpdateByRowIdStrings()

		if ( sqlLazyUpdateByRowIdString == null ) {
			throw new AssertionFailure( "no update by row id" );
		}
		String[] result = new String[getTableSpan()];
		result[0] = sqlLazyUpdateByRowIdString;
		for ( int i = 1; i < getTableSpan(); i++ ) {
			result[i] = sqlLazyUpdateStrings[i];
		}
		return result;
	
protected java.lang.String[]getSQLLazyUpdateStrings()

		return sqlLazyUpdateStrings;
	
protected java.lang.StringgetSQLSnapshotSelectString()

		return sqlSnapshotSelectString;
	
protected java.lang.String[]getSQLUpdateByRowIdStrings()

		if ( sqlUpdateByRowIdString == null ) {
			throw new AssertionFailure( "no update by row id" );
		}
		String[] result = new String[getTableSpan() + 1];
		result[0] = sqlUpdateByRowIdString;
		System.arraycopy( sqlUpdateStrings, 0, result, 1, getTableSpan() );
		return result;
	
protected java.lang.String[]getSQLUpdateStrings()

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

		return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
	
public java.lang.StringgetSelectByUniqueKeyString(java.lang.String propertyName)

		return new SimpleSelect( getFactory().getDialect() )
			.setTableName( getTableName(0) )
			.addColumns( getKeyColumns(0) )
			.addCondition( getPropertyColumnNames(propertyName), "=?" )
			.toStatementString();
	
protected java.lang.StringgetSequentialSelect(java.lang.String entityName)

		throw new UnsupportedOperationException("no sequential selects");
	
protected java.lang.String[]getSubclassColumnAliasClosure()

		return subclassColumnAliasClosure;
	
protected java.lang.String[]getSubclassColumnClosure()

		return subclassColumnClosure;
	
protected boolean[]getSubclassColumnLazyiness()

		return subclassColumnLazyClosure;
	
protected abstract int[]getSubclassColumnTableNumberClosure()

private java.lang.StringgetSubclassEntityName(java.lang.Class clazz)

		return ( String ) entityNameBySubclass.get( clazz );
	
public EntityPersistergetSubclassEntityPersister(java.lang.Object instance, org.hibernate.engine.SessionFactoryImplementor factory, org.hibernate.EntityMode entityMode)

		if ( !hasSubclasses() ) {
			return this;
		}
		else {
			// TODO : really need a way to do something like :
			//      getTuplizer(entityMode).determineConcreteSubclassEntityName(instance)
			Class clazz = instance.getClass();
			if ( clazz == getMappedClass( entityMode ) ) {
				return this;
			}
			else {
				String subclassEntityName = getSubclassEntityName( clazz );
				if ( subclassEntityName == null ) {
					throw new HibernateException(
							"instance not of expected entity type: " + clazz.getName() +
							" is not a: " + getEntityName()
						);
				}
				else {
					return factory.getEntityPersister( subclassEntityName );
				}
			}
		}
	
protected java.lang.String[]getSubclassFormulaAliasClosure()

		return subclassFormulaAliasClosure;
	
protected java.lang.String[]getSubclassFormulaClosure()

		return subclassFormulaClosure;
	
protected boolean[]getSubclassFormulaLazyiness()

		return subclassFormulaLazyClosure;
	
protected abstract int[]getSubclassFormulaTableNumberClosure()

protected java.lang.String[]getSubclassFormulaTemplateClosure()

		return subclassFormulaTemplateClosure;
	
public java.lang.String[]getSubclassPropertyColumnAliases(java.lang.String propertyName, java.lang.String suffix)

		String rawAliases[] = ( String[] ) subclassPropertyAliases.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;
	
protected java.lang.String[][]getSubclassPropertyColumnNameClosure()

		return subclassPropertyColumnNameClosure;
	
public java.lang.String[]getSubclassPropertyColumnNames(int i)

		return subclassPropertyColumnNameClosure[i];
	
public java.lang.String[]getSubclassPropertyColumnNames(java.lang.String propertyName)

		//TODO: should we allow suffixes on these ?
		return ( String[] ) subclassPropertyColumnNames.get( propertyName );
	
public DeclarergetSubclassPropertyDeclarer(java.lang.String propertyPath)

		int tableIndex = getSubclassPropertyTableNumber( propertyPath );
		if ( tableIndex == 0 ) {
			return Declarer.CLASS;
		}
		else if ( isClassOrSuperclassTable( tableIndex ) ) {
			return Declarer.SUPERCLASS;
		}
		else {
			return Declarer.SUBCLASS;
		}
	
protected java.lang.String[][]getSubclassPropertyFormulaTemplateClosure()

		return subclassPropertyFormulaTemplateClosure;
	
private intgetSubclassPropertyIndex(java.lang.String propertyName)

		return ArrayHelper.indexOf(subclassPropertyNameClosure, propertyName);
	
public java.lang.StringgetSubclassPropertyName(int i)

		return subclassPropertyNameClosure[i];
	
protected java.lang.String[]getSubclassPropertyNameClosure()

		return subclassPropertyNameClosure;
	
protected java.lang.String[]getSubclassPropertySubclassNameClosure()

		return subclassPropertySubclassNameClosure;
	
protected abstract intgetSubclassPropertyTableNumber(int i)

public intgetSubclassPropertyTableNumber(java.lang.String propertyPath)
Warning: When there are duplicated property names in the subclasses of the class, this method may return the wrong table number for the duplicated subclass property (note that SingleTableEntityPersister defines an overloaded form which takes the entity name.

		String rootPropertyName = StringHelper.root(propertyPath);
		Type type = propertyMapping.toType(rootPropertyName);
		if ( type.isAssociationType() ) {
			AssociationType assocType = ( AssociationType ) type;
			if ( assocType.useLHSPrimaryKey() ) {
				// performance op to avoid the array search
				return 0;
			}
			else if ( type.isCollectionType() ) {
				// properly handle property-ref-based associations
				rootPropertyName = assocType.getLHSPropertyName();
			}
		}
		//Enable for HHH-440, which we don't like:
		/*if ( type.isComponentType() && !propertyName.equals(rootPropertyName) ) {
			String unrooted = StringHelper.unroot(propertyName);
			int idx = ArrayHelper.indexOf( getSubclassColumnClosure(), unrooted );
			if ( idx != -1 ) {
				return getSubclassColumnTableNumberClosure()[idx];
			}
		}*/
		int index = ArrayHelper.indexOf( getSubclassPropertyNameClosure(), rootPropertyName); //TODO: optimize this better!
		return index==-1 ? 0 : getSubclassPropertyTableNumber(index);
	
public org.hibernate.type.TypegetSubclassPropertyType(int i)

		return subclassPropertyTypeClosure[i];
	
protected org.hibernate.type.Type[]getSubclassPropertyTypeClosure()

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

public abstract java.lang.StringgetSubclassTableName(int j)

protected abstract intgetSubclassTableSpan()

private boolean[]getTableHasColumns()

		return tableHasColumns;
	
protected abstract java.lang.StringgetTableName(int j)

protected abstract intgetTableSpan()

protected boolean[]getTableUpdateNeeded(int[] dirtyProperties, boolean hasDirtyCollection)
Decide which tables need to be updated.

The return here is an array of boolean values with each index corresponding to a given table in the scope of this persister.

param
dirtyProperties The indices of all the entity properties considered dirty.
param
hasDirtyCollection Whether any collections owned by the entity which were considered dirty.
return
Array of booleans indicating which table require updating.


		if ( dirtyProperties == null ) {
			return getTableHasColumns(); // for objects that came in via update()
		}
		else {
			boolean[] updateability = getPropertyUpdateability();
			int[] propertyTableNumbers = getPropertyTableNumbers();
			boolean[] tableUpdateNeeded = new boolean[ getTableSpan() ];
			for ( int i = 0; i < dirtyProperties.length; i++ ) {
				int property = dirtyProperties[i];
				int table = propertyTableNumbers[property];
				tableUpdateNeeded[table] = tableUpdateNeeded[table] ||
						( getPropertyColumnSpan(property) > 0 && updateability[property] );
			}
			if ( isVersioned() ) {
				tableUpdateNeeded[0] = tableUpdateNeeded[0] ||
					Versioning.isVersionIncrementRequired( dirtyProperties, hasDirtyCollection, getPropertyVersionability() );
			}
			return tableUpdateNeeded;
		}
	
public java.lang.StringgetTemporaryIdTableDDL()

		return temporaryIdTableDDL;
	
public java.lang.StringgetTemporaryIdTableName()

		return temporaryIdTableName;
	
protected org.hibernate.tuple.entity.EntityTuplizergetTuplizer(org.hibernate.engine.SessionImplementor session)

		return getTuplizer( session.getEntityMode() );
	
protected org.hibernate.tuple.entity.EntityTuplizergetTuplizer(org.hibernate.EntityMode entityMode)

		return entityMetamodel.getTuplizer( entityMode );
	
public org.hibernate.type.TypegetType()

		return entityMetamodel.getEntityType();
	
private java.lang.String[]getUpdateStrings(boolean byRowId, boolean lazy)

		if ( byRowId ) {
			return lazy ? getSQLLazyUpdateByRowIdStrings() : getSQLUpdateByRowIdStrings();
		}
		else {
			return lazy ? getSQLLazyUpdateStrings() : getSQLUpdateStrings();
		}
	
public java.lang.ObjectgetVersion(java.lang.Object object, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).getVersion( object );
	
public java.lang.StringgetVersionColumnName()

		return versionColumnName;
	
public java.util.ComparatorgetVersionComparator()

		return isVersioned() ? getVersionType().getComparator() : null;
	
public intgetVersionProperty()

		return entityMetamodel.getVersionPropertyIndex();
	
protected java.lang.StringgetVersionSelectString()

		return sqlVersionSelectString;
	
public org.hibernate.type.VersionTypegetVersionType()

		return ( VersionType ) locateVersionType();
	
protected java.lang.StringgetVersionedTableName()

		return getTableName( 0 );
	
public org.hibernate.EntityModeguessEntityMode(java.lang.Object object)

		return entityMetamodel.guessEntityMode(object);
	
public booleanhasCache()

		return cache != null;
	
public booleanhasCascades()

		return entityMetamodel.hasCascades();
	
public booleanhasCollections()

		return entityMetamodel.hasCollections();
	
protected booleanhasEmbeddedCompositeIdentifier()

		return entityMetamodel.getIdentifierProperty().isEmbedded();
	
protected booleanhasFormulaProperties()

		return hasFormulaProperties;
	
private booleanhasIdentifierMapper()

		return entityMetamodel.getIdentifierProperty().hasIdentifierMapper();
	
public booleanhasIdentifierProperty()

		return !entityMetamodel.getIdentifierProperty().isVirtual();
	
public booleanhasInsertGeneratedProperties()

		return entityMetamodel.hasInsertGeneratedValues();
	
public booleanhasLazyProperties()

		return entityMetamodel.hasLazyProperties();
	
public booleanhasMutableProperties()

		return entityMetamodel.hasMutableProperties();
	
public booleanhasNaturalIdentifier()

		return entityMetamodel.hasNaturalIdentifier();
	
public booleanhasProxy()

		return entityMetamodel.isLazy();
	
public booleanhasRowId()

		return rowIdName != null;
	
public booleanhasSequentialSelect()

		return false;
	
public booleanhasSubclasses()

		return entityMetamodel.hasSubclasses();
	
public booleanhasSubselectLoadableCollections()

		return hasSubselectLoadableCollections;
	
public booleanhasUninitializedLazyProperties(java.lang.Object object, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).hasUninitializedLazyProperties( object );
	
public booleanhasUpdateGeneratedProperties()

		return entityMetamodel.hasUpdateGeneratedValues();
	
protected booleanhasWhere()

		return sqlWhereString != null;
	
public java.lang.Object[]hydrate(java.sql.ResultSet rs, java.io.Serializable id, java.lang.Object object, Loadable rootLoadable, java.lang.String[][] suffixedPropertyColumns, boolean allProperties, org.hibernate.engine.SessionImplementor session)
Unmarshall the fields of a persistent instance from a result set, without resolving associations or collections. Question: should this really be here, or should it be sent back to Loader?


		if ( log.isTraceEnabled() ) {
			log.trace( "Hydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
		}

		final AbstractEntityPersister rootPersister = (AbstractEntityPersister) rootLoadable;

		final boolean hasDeferred = rootPersister.hasSequentialSelect();
		PreparedStatement sequentialSelect = null;
		ResultSet sequentialResultSet = null;
		boolean sequentialSelectEmpty = false;
		try {

			if ( hasDeferred ) {
				final String sql = rootPersister.getSequentialSelect( getEntityName() );
				if ( sql != null ) {
					//TODO: I am not so sure about the exception handling in this bit!
					sequentialSelect = session.getBatcher().prepareSelectStatement( sql );
					rootPersister.getIdentifierType().nullSafeSet( sequentialSelect, id, 1, session );
					sequentialResultSet = sequentialSelect.executeQuery();
					if ( !sequentialResultSet.next() ) {
						// TODO: Deal with the "optional" attribute in the <join> mapping;
						// this code assumes that optional defaults to "true" because it
						// doesn't actually seem to work in the fetch="join" code
						//
						// Note that actual proper handling of optional-ality here is actually
						// more involved than this patch assumes.  Remember that we might have
						// multiple <join/> mappings associated with a single entity.  Really
						// a couple of things need to happen to properly handle optional here:
						//  1) First and foremost, when handling multiple <join/>s, we really
						//      should be using the entity root table as the driving table;
						//      another option here would be to choose some non-optional joined
						//      table to use as the driving table.  In all likelihood, just using
						//      the root table is much simplier
						//  2) Need to add the FK columns corresponding to each joined table
						//      to the generated select list; these would then be used when
						//      iterating the result set to determine whether all non-optional
						//      data is present
						// My initial thoughts on the best way to deal with this would be
						// to introduce a new SequentialSelect abstraction that actually gets
						// generated in the persisters (ok, SingleTable...) and utilized here.
						// It would encapsulated all this required optional-ality checking...
						sequentialSelectEmpty = true;
					}
				}
			}

			final String[] propNames = getPropertyNames();
			final Type[] types = getPropertyTypes();
			final Object[] values = new Object[types.length];
			final boolean[] laziness = getPropertyLaziness();
			final String[] propSubclassNames = getSubclassPropertySubclassNameClosure();

			for ( int i = 0; i < types.length; i++ ) {
				if ( !propertySelectable[i] ) {
					values[i] = BackrefPropertyAccessor.UNKNOWN;
				}
				else if ( allProperties || !laziness[i] ) {
					//decide which ResultSet to get the property value from:
					final boolean propertyIsDeferred = hasDeferred &&
							rootPersister.isSubclassPropertyDeferred( propNames[i], propSubclassNames[i] );
					if ( propertyIsDeferred && sequentialSelectEmpty ) {
						values[i] = null;
					}
					else {
						final ResultSet propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs;
						final String[] cols = propertyIsDeferred ? propertyColumnAliases[i] : suffixedPropertyColumns[i];
						values[i] = types[i].hydrate( propertyResultSet, cols, session, object );
					}
				}
				else {
					values[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
				}
			}

			if ( sequentialResultSet != null ) {
				sequentialResultSet.close();
			}

			return values;

		}
		finally {
			if ( sequentialSelect != null ) {
				session.getBatcher().closeStatement( sequentialSelect );
			}
		}
	
public java.lang.StringidentifierSelectFragment(java.lang.String name, java.lang.String suffix)

		return new SelectFragment()
				.setSuffix( suffix )
				.addColumns( name, getIdentifierColumnNames(), getIdentifierAliases() )
				.toFragmentString()
				.substring( 2 ); //strip leading ", "
	
public booleanimplementsLifecycle(org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).isLifecycleImplementor();
	
public booleanimplementsValidatable(org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).isValidatableImplementor();
	
private voidinitDiscriminatorPropertyPath(org.hibernate.engine.Mapping mapping)

		propertyMapping.initPropertyPaths( ENTITY_CLASS,
				getDiscriminatorType(),
				new String[]{getDiscriminatorColumnName()},
				new String[]{getDiscriminatorFormulaTemplate()},
				getFactory() );
	
private voidinitIdentifierPropertyPaths(org.hibernate.engine.Mapping mapping)

		String idProp = getIdentifierPropertyName();
		if ( idProp != null ) {
			propertyMapping.initPropertyPaths( idProp, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
		}
		if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
			propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
		}
		if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
			propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
		}
	
protected voidinitLockers()

		lockers.put( LockMode.READ, generateLocker( LockMode.READ ) );
		lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
		lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
		lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
	
private voidinitOrdinaryPropertyPaths(org.hibernate.engine.Mapping mapping)

		for ( int i = 0; i < getSubclassPropertyNameClosure().length; i++ ) {
			propertyMapping.initPropertyPaths( getSubclassPropertyNameClosure()[i],
					getSubclassPropertyTypeClosure()[i],
					getSubclassPropertyColumnNameClosure()[i],
					getSubclassPropertyFormulaTemplateClosure()[i],
					mapping );
		}
	
protected voidinitPropertyPaths(org.hibernate.engine.Mapping mapping)

		initOrdinaryPropertyPaths(mapping);
		initOrdinaryPropertyPaths(mapping); //do two passes, for collection property-ref!
		initIdentifierPropertyPaths(mapping);
		if ( entityMetamodel.isPolymorphic() ) {
			initDiscriminatorPropertyPath( mapping );
		}
	
protected voidinitSubclassPropertyAliasesMap(org.hibernate.mapping.PersistentClass model)
Must be called by subclasses, at the end of their constructors


		// ALIASES
		internalInitSubclassPropertyAliasesMap( null, model.getSubclassPropertyClosureIterator() );

		// aliases for identifier ( alias.id ); skip if the entity defines a non-id property named 'id'
		if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
			subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
			subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
		}

		// aliases named identifier ( alias.idname )
		if ( hasIdentifierProperty() ) {
			subclassPropertyAliases.put( getIdentifierPropertyName(), getIdentifierAliases() );
			subclassPropertyColumnNames.put( getIdentifierPropertyName(), getIdentifierColumnNames() );
		}

		// aliases for composite-id's
		if ( getIdentifierType().isComponentType() ) {
			// Fetch embedded identifiers propertynames from the "virtual" identifier component
			AbstractComponentType componentId = ( AbstractComponentType ) getIdentifierType();
			String[] idPropertyNames = componentId.getPropertyNames();
			String[] idAliases = getIdentifierAliases();
			String[] idColumnNames = getIdentifierColumnNames();

			for ( int i = 0; i < idPropertyNames.length; i++ ) {
				if ( entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
					subclassPropertyAliases.put(
							ENTITY_ID + "." + idPropertyNames[i],
							new String[] { idAliases[i] }
					);
					subclassPropertyColumnNames.put(
							ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
							new String[] { idColumnNames[i] }
					);
				}
//				if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
				if ( hasIdentifierProperty() ) {
					subclassPropertyAliases.put(
							getIdentifierPropertyName() + "." + idPropertyNames[i],
							new String[] { idAliases[i] }
					);
					subclassPropertyColumnNames.put(
							getIdentifierPropertyName() + "." + idPropertyNames[i],
							new String[] { idColumnNames[i] }
					);
				}
				else {
					// embedded composite ids ( alias.idname1, alias.idname2 )
					subclassPropertyAliases.put( idPropertyNames[i], new String[] { idAliases[i] } );
					subclassPropertyColumnNames.put( idPropertyNames[i],  new String[] { idColumnNames[i] } );
				}
			}
		}

		if ( entityMetamodel.isPolymorphic() ) {
			subclassPropertyAliases.put( ENTITY_CLASS, new String[] { getDiscriminatorAlias() } );
			subclassPropertyColumnNames.put( ENTITY_CLASS, new String[] { getDiscriminatorColumnName() } );
		}

	
private java.lang.ObjectinitializeLazyPropertiesFromCache(java.lang.String fieldName, java.lang.Object entity, org.hibernate.engine.SessionImplementor session, org.hibernate.engine.EntityEntry entry, org.hibernate.cache.entry.CacheEntry cacheEntry)


		log.trace("initializing lazy properties from second-level cache");

		Object result = null;
		Serializable[] disassembledValues = cacheEntry.getDisassembledState();
		final Object[] snapshot = entry.getLoadedState();
		for ( int j = 0; j < lazyPropertyNames.length; j++ ) {
			final Object propValue = lazyPropertyTypes[j].assemble(
					disassembledValues[ lazyPropertyNumbers[j] ],
					session,
					entity
				);
			if ( initializeLazyProperty( fieldName, entity, session, snapshot, j, propValue ) ) {
				result = propValue;
			}
		}

		log.trace( "done initializing lazy properties" );

		return result;
	
private java.lang.ObjectinitializeLazyPropertiesFromDatastore(java.lang.String fieldName, java.lang.Object entity, org.hibernate.engine.SessionImplementor session, java.io.Serializable id, org.hibernate.engine.EntityEntry entry)


		if ( !hasLazyProperties() ) {
			throw new AssertionFailure("no lazy properties");
		}

		log.trace("initializing lazy properties from datastore");

		try {

			Object result = null;
			PreparedStatement ps = null;
			ResultSet rs = null;
			try {
				final String lazySelect = getSQLLazySelectString();
				if ( lazySelect != null ) {
					// null sql means that the only lazy properties
					// are shared PK one-to-one associations which are
					// handled differently in the Type#nullSafeGet code...
					ps = session.getBatcher().prepareSelectStatement(lazySelect);
					getIdentifierType().nullSafeSet( ps, id, 1, session );
					rs = session.getBatcher().getResultSet( ps );
					rs.next();
				}
				final Object[] snapshot = entry.getLoadedState();
				for ( int j = 0; j < lazyPropertyNames.length; j++ ) {
					Object propValue = lazyPropertyTypes[j].nullSafeGet( rs, lazyPropertyColumnAliases[j], session, entity );
					if ( initializeLazyProperty( fieldName, entity, session, snapshot, j, propValue ) ) {
						result = propValue;
					}
				}
			}
			finally {
				if ( rs != null ) {
					session.getBatcher().closeQueryStatement( ps, rs );
				}
				else if ( ps != null ) {
					session.getBatcher().closeStatement( ps );
				}
			}

			log.trace( "done initializing lazy properties" );

			return result;

		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not initialize lazy properties: " +
					MessageHelper.infoString( this, id, getFactory() ),
					getSQLLazySelectString()
				);
		}
	
public java.lang.ObjectinitializeLazyProperty(java.lang.String fieldName, java.lang.Object entity, org.hibernate.engine.SessionImplementor session)


		final Serializable id = session.getContextEntityIdentifier( entity );

		final EntityEntry entry = session.getPersistenceContext().getEntry( entity );
		if ( entry == null ) {
			throw new HibernateException( "entity is not associated with the session: " + id );
		}

		if ( log.isTraceEnabled() ) {
			log.trace(
					"initializing lazy properties of: " +
					MessageHelper.infoString( this, id, getFactory() ) +
					", field access: " + fieldName
				);
		}

		if ( hasCache() ) {
			CacheKey cacheKey = new CacheKey(id, getIdentifierType(), getEntityName(), session.getEntityMode(), getFactory() );
			Object ce = getCache().get( cacheKey, session.getTimestamp() );
			if (ce!=null) {
				CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure(ce, factory);
				if ( !cacheEntry.areLazyPropertiesUnfetched() ) {
					//note early exit here:
					return initializeLazyPropertiesFromCache( fieldName, entity, session, entry, cacheEntry );
				}
			}
		}

		return initializeLazyPropertiesFromDatastore( fieldName, entity, session, id, entry );

	
private booleaninitializeLazyProperty(java.lang.String fieldName, java.lang.Object entity, org.hibernate.engine.SessionImplementor session, java.lang.Object[] snapshot, int j, java.lang.Object propValue)

		setPropertyValue( entity, lazyPropertyNumbers[j], propValue, session.getEntityMode() );
		if (snapshot != null) {
			// object have been loaded with setReadOnly(true); HHH-2236
			snapshot[ lazyPropertyNumbers[j] ] = lazyPropertyTypes[j].deepCopy( propValue, session.getEntityMode(), factory );
		}
		return fieldName.equals( lazyPropertyNames[j] );
	
protected java.io.Serializableinsert(java.lang.Object[] fields, boolean[] notNull, java.lang.String sql, java.lang.Object object, org.hibernate.engine.SessionImplementor session)
Perform an SQL INSERT, and then retrieve a generated identifier.

This form is used for PostInsertIdentifierGenerator-style ids (IDENTITY, select, etc).


		if ( log.isTraceEnabled() ) {
			log.trace( "Inserting entity: " + getEntityName() + " (native id)" );
			if ( isVersioned() ) {
				log.trace( "Version: " + Versioning.getVersion( fields, this ) );
			}
		}

		Binder binder = new Binder() {
			public void bindValues(PreparedStatement ps) throws SQLException {
				dehydrate( null, fields, notNull, propertyColumnInsertable, 0, ps, session );
			}
			public Object getEntity() {
				return object;
			}
		};
		return identityDelegate.performInsert( sql, session, binder );
	
protected voidinsert(java.io.Serializable id, java.lang.Object[] fields, boolean[] notNull, int j, java.lang.String sql, java.lang.Object object, org.hibernate.engine.SessionImplementor session)
Perform an SQL INSERT.

This for is used for all non-root tables as well as the root table in cases where the identifier value is known before the insert occurs.


		if ( isInverseTable( j ) ) {
			return;
		}

		//note: it is conceptually possible that a UserType could map null to
		//	  a non-null value, so the following is arguable:
		if ( isNullableTable( j ) && isAllNull( fields, j ) ) {
			return;
		}

		if ( log.isTraceEnabled() ) {
			log.trace( "Inserting entity: " + MessageHelper.infoString( this, id, getFactory() ) );
			if ( j == 0 && isVersioned() ) {
				log.trace( "Version: " + Versioning.getVersion( fields, this ) );
			}
		}

		Expectation expectation = Expectations.appropriateExpectation( insertResultCheckStyles[j] );
		boolean callable = isInsertCallable( j );
		// we can't batch joined inserts, *especially* not if it is an identity insert;
		// nor can we batch statements where the expectation is based on an output param
		final boolean useBatch = j == 0 && expectation.canBeBatched();
		try {

			// Render the SQL query
			final PreparedStatement insert;
			if ( useBatch ) {
				if ( callable ) {
					insert = session.getBatcher().prepareBatchCallableStatement( sql );
				}
				else {
					insert = session.getBatcher().prepareBatchStatement( sql );
				}
			}
			else {
				if ( callable ) {
					insert = session.getBatcher().prepareCallableStatement( sql );
				}
				else {
					insert = session.getBatcher().prepareStatement( sql );
				}
			}

			try {
				int index = 1;
				index += expectation.prepare( insert );

				// Write the values of fields onto the prepared statement - we MUST use the state at the time the
				// insert was issued (cos of foreign key constraints). Not necessarily the object's current state

				dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, insert, session, index );

				if ( useBatch ) {
					// TODO : shouldnt inserts be Expectations.NONE?
					session.getBatcher().addToBatch( expectation );
				}
				else {
					expectation.verifyOutcome( insert.executeUpdate(), insert, -1 );
				}

			}
			catch ( SQLException sqle ) {
				if ( useBatch ) {
					session.getBatcher().abortBatch( sqle );
				}
				throw sqle;
			}
			finally {
				if ( !useBatch ) {
					session.getBatcher().closeStatement( insert );
				}
			}
		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not insert: " + MessageHelper.infoString( this ),
					sql
				);
		}

	
public java.io.Serializableinsert(java.lang.Object[] fields, java.lang.Object object, org.hibernate.engine.SessionImplementor session)


		final int span = getTableSpan();
		final Serializable id;
		if ( entityMetamodel.isDynamicInsert() ) {
			// For the case of dynamic-insert="true", we need to generate the INSERT SQL
			boolean[] notNull = getPropertiesToInsert( fields );
			id = insert( fields, notNull, generateInsertString( true, notNull ), object, session );
			for ( int j = 1; j < span; j++ ) {
				insert( id, fields, notNull, j, generateInsertString( notNull, j ), object, session );
			}
		}
		else {
			// For the case of dynamic-insert="false", use the static SQL
			id = insert( fields, getPropertyInsertability(), getSQLIdentityInsertString(), object, session );
			for ( int j = 1; j < span; j++ ) {
				insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
			}
		}
		return id;
	
public voidinsert(java.io.Serializable id, java.lang.Object[] fields, java.lang.Object object, org.hibernate.engine.SessionImplementor session)


		final int span = getTableSpan();
		if ( entityMetamodel.isDynamicInsert() ) {
			// For the case of dynamic-insert="true", we need to generate the INSERT SQL
			boolean[] notNull = getPropertiesToInsert( fields );
			for ( int j = 0; j < span; j++ ) {
				insert( id, fields, notNull, j, generateInsertString( notNull, j ), object, session );
			}
		}
		else {
			// For the case of dynamic-insert="false", use the static SQL
			for ( int j = 0; j < span; j++ ) {
				insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
			}
		}
	
public java.lang.Objectinstantiate(java.io.Serializable id, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).instantiate( id );
	
private voidinternalInitSubclassPropertyAliasesMap(java.lang.String path, java.util.Iterator propertyIterator)

		while ( propertyIterator.hasNext() ) {

			Property prop = ( Property ) propertyIterator.next();
			String propname = path == null ? prop.getName() : path + "." + prop.getName();
			if ( prop.isComposite() ) {
				Component component = ( Component ) prop.getValue();
				Iterator compProps = component.getPropertyIterator();
				internalInitSubclassPropertyAliasesMap( propname, compProps );
			}
			else {
				String[] aliases = new String[prop.getColumnSpan()];
				String[] cols = new String[prop.getColumnSpan()];
				Iterator colIter = prop.getColumnIterator();
				int l = 0;
				while ( colIter.hasNext() ) {
					Selectable thing = ( Selectable ) colIter.next();
					aliases[l] = thing.getAlias( getFactory().getDialect(), prop.getValue().getTable() );
					cols[l] = thing.getText( getFactory().getDialect() ); // TODO: skip formulas?
					l++;
				}

				subclassPropertyAliases.put( propname, aliases );
				subclassPropertyColumnNames.put( propname, cols );
			}
		}

	
public booleanisAbstract()

		return entityMetamodel.isAbstract();
	
private booleanisAllNull(java.lang.Object[] array, int tableNumber)

		for ( int i = 0; i < array.length; i++ ) {
			if ( isPropertyOfTable( i, tableNumber ) && array[i] != null ) {
				return false;
			}
		}
		return true;
	
public booleanisBatchLoadable()

		return batchSize > 1;
	
public booleanisBatchable()

		return optimisticLockMode()==Versioning.OPTIMISTIC_LOCK_NONE ||
			( !isVersioned() && optimisticLockMode()==Versioning.OPTIMISTIC_LOCK_VERSION ) ||
			getFactory().getSettings().isJdbcBatchVersionedData();
	
public booleanisCacheInvalidationRequired()
We can't immediately add to the cache if we have formulas which must be evaluated, or if we have the possibility of two concurrent updates to the same item being merged on the database. This can happen if (a) the item is not versioned and either (b) we have dynamic update enabled or (c) we have multiple tables holding the state of the item.

		return hasFormulaProperties() ||
				( !isVersioned() && ( entityMetamodel.isDynamicUpdate() || getTableSpan() > 1 ) );
	
protected abstract booleanisClassOrSuperclassTable(int j)

public booleanisCollection()

		return false;
	
public booleanisDefinedOnSubclass(int i)

		return propertyDefinedOnSubclass[i];
	
protected booleanisDeleteCallable(int j)

		return deleteCallable[j];
	
public booleanisExplicitPolymorphism()

		return entityMetamodel.isExplicitPolymorphism();
	
public booleanisIdentifierAssignedByInsert()

		return entityMetamodel.getIdentifierProperty().isIdentifierAssignedByInsert();
	
public booleanisInherited()

		return entityMetamodel.isInherited();
	
protected booleanisInsertCallable(int j)

		return insertCallable[j];
	
public booleanisInstance(java.lang.Object object, org.hibernate.EntityMode entityMode)

		return getTuplizer( entityMode ).isInstance( object );
	
public booleanisInstrumented(org.hibernate.EntityMode entityMode)

		EntityTuplizer tuplizer = entityMetamodel.getTuplizerOrNull(entityMode);
		return tuplizer!=null && tuplizer.isInstrumented();
	
protected booleanisInverseSubclassTable(int j)

		return false;
	
protected booleanisInverseTable(int j)

		return false;
	
public booleanisLazyPropertiesCacheable()

		return isLazyPropertiesCacheable;
	
public booleanisMultiTable()

		return false;
	
public booleanisMutable()

		return entityMetamodel.isMutable();
	
protected booleanisNullableSubclassTable(int j)

		return false;
	
protected booleanisNullableTable(int j)

		return false;
	
public booleanisPolymorphic()

		return entityMetamodel.isPolymorphic();
	
protected abstract booleanisPropertyOfTable(int property, int j)

public booleanisSelectBeforeUpdateRequired()

		return entityMetamodel.isSelectBeforeUpdate();
	
public booleanisSubclassEntityName(java.lang.String entityName)

		return entityMetamodel.getSubclassEntityNames().contains(entityName);
	
protected booleanisSubclassPropertyDeferred(java.lang.String propertyName, java.lang.String entityName)

		return false;
	
public booleanisSubclassPropertyNullable(int i)

		return subclassPropertyNullabilityClosure[i];
	
protected booleanisSubclassTableLazy(int j)

		return false;
	
protected booleanisSubclassTableSequentialSelect(int j)

		return false;
	
protected abstract booleanisTableCascadeDeleteEnabled(int j)

public java.lang.BooleanisTransient(java.lang.Object entity, org.hibernate.engine.SessionImplementor session)

		final Serializable id;
		if ( canExtractIdOutOfEntity() ) {
			id = getIdentifier( entity, session.getEntityMode() );
		}
		else {
			id = null;
		}
		// we *always* assume an instance with a null
		// identifier or no identifier property is unsaved!
		if ( id == null ) {
			return Boolean.TRUE;
		}

		// check the version unsaved-value, if appropriate
		final Object version = getVersion( entity, session.getEntityMode() );
		if ( isVersioned() ) {
			// let this take precedence if defined, since it works for
			// assigned identifiers
			Boolean result = entityMetamodel.getVersionProperty()
					.getUnsavedValue().isUnsaved( version );
			if ( result != null ) {
				return result;
			}
		}

		// check the id unsaved-value
		Boolean result = entityMetamodel.getIdentifierProperty()
				.getUnsavedValue().isUnsaved( id );
		if ( result != null ) {
			return result;
		}

		// check to see if it is in the second-level cache
		if ( hasCache() ) {
			CacheKey ck = new CacheKey(
					id,
					getIdentifierType(),
					getRootEntityName(),
					session.getEntityMode(),
					session.getFactory()
				);
			if ( getCache().get( ck, session.getTimestamp() ) != null ) {
				return Boolean.FALSE;
			}
		}

		return null;
	
protected booleanisUpdateCallable(int j)

		return updateCallable[j];
	
public booleanisVersionPropertyGenerated()

		return isVersioned() && ( getPropertyUpdateGenerationInclusions() [ getVersionProperty() ] != ValueInclusion.NONE );
	
public booleanisVersionPropertyInsertable()

		return isVersioned() && getPropertyInsertability() [ getVersionProperty() ];
	
public booleanisVersioned()

		return entityMetamodel.isVersioned();
	
public java.lang.Objectload(java.io.Serializable id, java.lang.Object optionalObject, org.hibernate.LockMode lockMode, org.hibernate.engine.SessionImplementor session)
Load an instance using either the forUpdateLoader or the outer joining loader, depending upon the value of the lock parameter


		if ( log.isTraceEnabled() ) {
			log.trace(
					"Fetching entity: " +
					MessageHelper.infoString( this, id, getFactory() )
				);
		}

		final UniqueEntityLoader loader = getAppropriateLoader( lockMode, session );
		return loader.load( id, optionalObject, session );
	
public java.lang.ObjectloadByUniqueKey(java.lang.String propertyName, java.lang.Object uniqueKey, org.hibernate.engine.SessionImplementor session)

		return getAppropriateUniqueKeyLoader( propertyName, session.getEnabledFilters() )
				.loadByUniqueKey( session, uniqueKey );
	
private org.hibernate.type.TypelocateVersionType()

		return entityMetamodel.getVersionProperty() == null ?
				null :
				entityMetamodel.getVersionProperty().getType();
	
public voidlock(java.io.Serializable id, java.lang.Object version, java.lang.Object object, org.hibernate.LockMode lockMode, org.hibernate.engine.SessionImplementor session)

		getLocker( lockMode ).lock( id, version, object, session );
	
private voidlogDirtyProperties(int[] props)

		if ( log.isTraceEnabled() ) {
			for ( int i = 0; i < props.length; i++ ) {
				String propertyName = entityMetamodel.getProperties()[ props[i] ].getName();
				log.trace( StringHelper.qualify( getEntityName(), propertyName ) + " is dirty" );
			}
		}
	
protected voidlogStaticSQL()

		if ( log.isDebugEnabled() ) {
			log.debug( "Static SQL for entity: " + getEntityName() );
			if ( sqlLazySelectString != null ) {
				log.debug( " Lazy select: " + sqlLazySelectString );
			}
			if ( sqlVersionSelectString != null ) {
				log.debug( " Version select: " + sqlVersionSelectString );
			}
			if ( sqlSnapshotSelectString != null ) {
				log.debug( " Snapshot select: " + sqlSnapshotSelectString );
			}
			for ( int j = 0; j < getTableSpan(); j++ ) {
				log.debug( " Insert " + j + ": " + getSQLInsertStrings()[j] );
				log.debug( " Update " + j + ": " + getSQLUpdateStrings()[j] );
				log.debug( " Delete " + j + ": " + getSQLDeleteStrings()[j] );

			}
			if ( sqlIdentityInsertString != null ) {
				log.debug( " Identity insert: " + sqlIdentityInsertString );
			}
			if ( sqlUpdateByRowIdString != null ) {
				log.debug( " Update by row id (all fields): " + sqlUpdateByRowIdString );
			}
			if ( sqlLazyUpdateByRowIdString != null ) {
				log.debug( " Update by row id (non-lazy fields): " + sqlLazyUpdateByRowIdString );
			}
			if ( sqlInsertGeneratedValuesSelectString != null ) {
				log.debug( "Insert-generated property select: " + sqlInsertGeneratedValuesSelectString );
			}
			if ( sqlUpdateGeneratedValuesSelectString != null ) {
				log.debug( "Update-generated property select: " + sqlUpdateGeneratedValuesSelectString );
			}
		}
	
public java.lang.StringoneToManyFilterFragment(java.lang.String alias)

		return "";
	
protected final intoptimisticLockMode()

		return entityMetamodel.getOptimisticLockMode();
	
protected voidpostConstruct(org.hibernate.engine.Mapping mapping)

		initPropertyPaths(mapping);

		//insert/update/delete SQL
		final int joinSpan = getTableSpan();
		sqlDeleteStrings = new String[joinSpan];
		sqlInsertStrings = new String[joinSpan];
		sqlUpdateStrings = new String[joinSpan];
		sqlLazyUpdateStrings = new String[joinSpan];

		sqlUpdateByRowIdString = rowIdName == null ?
				null :
				generateUpdateString( getPropertyUpdateability(), 0, true );
		sqlLazyUpdateByRowIdString = rowIdName == null ?
				null :
				generateUpdateString( getNonLazyPropertyUpdateability(), 0, true );

		for ( int j = 0; j < joinSpan; j++ ) {
			sqlInsertStrings[j] = customSQLInsert[j] == null ?
					generateInsertString( getPropertyInsertability(), j ) :
					customSQLInsert[j];
			sqlUpdateStrings[j] = customSQLUpdate[j] == null ?
					generateUpdateString( getPropertyUpdateability(), j, false ) :
					customSQLUpdate[j];
			sqlLazyUpdateStrings[j] = customSQLUpdate[j] == null ?
					generateUpdateString( getNonLazyPropertyUpdateability(), j, false ) :
					customSQLUpdate[j];
			sqlDeleteStrings[j] = customSQLDelete[j] == null ?
					generateDeleteString( j ) :
					customSQLDelete[j];
		}

		tableHasColumns = new boolean[joinSpan];
		for ( int j = 0; j < joinSpan; j++ ) {
			tableHasColumns[j] = sqlUpdateStrings[j] != null;
		}

		//select SQL
		sqlSnapshotSelectString = generateSnapshotSelectString();
		sqlLazySelectString = generateLazySelectString();
		sqlVersionSelectString = generateSelectVersionString();
		if ( hasInsertGeneratedProperties() ) {
			sqlInsertGeneratedValuesSelectString = generateInsertGeneratedValuesSelectString();
		}
		if ( hasUpdateGeneratedProperties() ) {
			sqlUpdateGeneratedValuesSelectString = generateUpdateGeneratedValuesSelectString();
		}
		if ( isIdentifierAssignedByInsert() ) {
			identityDelegate = ( ( PostInsertIdentifierGenerator ) getIdentifierGenerator() )
					.getInsertGeneratedIdentifierDelegate( this, getFactory().getDialect(), useGetGeneratedKeys() );
			sqlIdentityInsertString = customSQLInsert[0] == null
					? generateIdentityInsertString( getPropertyInsertability() )
					: customSQLInsert[0];
		}
		else {
			sqlIdentityInsertString = null;
		}

		logStaticSQL();

	
public voidpostInstantiate()


		createLoaders();
		createUniqueKeyLoaders();
		createQueryLoader();

	
private voidprocessGeneratedProperties(java.io.Serializable id, java.lang.Object entity, java.lang.Object[] state, org.hibernate.engine.SessionImplementor session, java.lang.String selectionSQL, org.hibernate.engine.ValueInclusion[] includeds)


		session.getBatcher().executeBatch(); //force immediate execution of the insert

		try {
			PreparedStatement ps = session.getBatcher().prepareSelectStatement( selectionSQL );
			ResultSet rs = null;
			try {
				getIdentifierType().nullSafeSet( ps, id, 1, session );
				rs = session.getBatcher().getResultSet( ps );
				if ( !rs.next() ) {
					throw new HibernateException(
							"Unable to locate row for retrieval of generated properties: " +
							MessageHelper.infoString( this, id, getFactory() )
						);
				}
				for ( int i = 0; i < getPropertySpan(); i++ ) {
					if ( includeds[i] != ValueInclusion.NONE ) {
						Object hydratedState = getPropertyTypes()[i].hydrate( rs, getPropertyAliases( "", i ), session, entity );
						state[i] = getPropertyTypes()[i].resolve( hydratedState, session, entity );
						setPropertyValue( entity, i, state[i], session.getEntityMode() );
					}
				}
			}
			finally {
				session.getBatcher().closeQueryStatement( ps, rs );
			}
		}
		catch( SQLException sqle ) {
			JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"unable to select generated column values",
					selectionSQL
			);
		}

	
public voidprocessInsertGeneratedProperties(java.io.Serializable id, java.lang.Object entity, java.lang.Object[] state, org.hibernate.engine.SessionImplementor session)

		if ( !hasInsertGeneratedProperties() ) {
			throw new AssertionFailure("no insert-generated properties");
		}
		processGeneratedProperties( id, entity, state, session, sqlInsertGeneratedValuesSelectString, getPropertyInsertGenerationInclusions() );
	
public voidprocessUpdateGeneratedProperties(java.io.Serializable id, java.lang.Object entity, java.lang.Object[] state, org.hibernate.engine.SessionImplementor session)

		if ( !hasUpdateGeneratedProperties() ) {
			throw new AssertionFailure("no update-generated properties");
		}
		processGeneratedProperties( id, entity, state, session, sqlUpdateGeneratedValuesSelectString, getPropertyUpdateGenerationInclusions() );
	
public java.lang.StringpropertySelectFragment(java.lang.String name, java.lang.String suffix, boolean allProperties)


		SelectFragment select = new SelectFragment()
				.setSuffix( suffix )
				.setUsedAliases( getIdentifierAliases() );

		int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
		String[] columnAliases = getSubclassColumnAliasClosure();
		String[] columns = getSubclassColumnClosure();
		for ( int i = 0; i < getSubclassColumnClosure().length; i++ ) {
			boolean selectable = ( allProperties || !subclassColumnLazyClosure[i] ) &&
				!isSubclassTableSequentialSelect( columnTableNumbers[i] ) &&
				subclassColumnSelectableClosure[i];
			if ( selectable ) {
				String subalias = generateTableAlias( name, columnTableNumbers[i] );
				select.addColumn( subalias, columns[i], columnAliases[i] );
			}
		}

		int[] formulaTableNumbers = getSubclassFormulaTableNumberClosure();
		String[] formulaTemplates = getSubclassFormulaTemplateClosure();
		String[] formulaAliases = getSubclassFormulaAliasClosure();
		for ( int i = 0; i < getSubclassFormulaTemplateClosure().length; i++ ) {
			boolean selectable = ( allProperties || !subclassFormulaLazyClosure[i] )
				&& !isSubclassTableSequentialSelect( formulaTableNumbers[i] );
			if ( selectable ) {
				String subalias = generateTableAlias( name, formulaTableNumbers[i] );
				select.addFormula( subalias, formulaTemplates[i], formulaAliases[i] );
			}
		}

		if ( entityMetamodel.hasSubclasses() ) {
			addDiscriminatorToSelect( select, name, suffix );
		}

		if ( hasRowId() ) {
			select.addColumn( name, rowIdName, ROWID_ALIAS );
		}

		return select.toFragmentString();
	
protected java.lang.StringrenderSelect(int[] tableNumbers, int[] columnNumbers, int[] formulaNumbers)


		Arrays.sort( tableNumbers ); //get 'em in the right order (not that it really matters)

		//render the where and from parts
		int drivingTable = tableNumbers[0];
		final String drivingAlias = generateTableAlias( getRootAlias(), drivingTable ); //we *could* regerate this inside each called method!
		final String where = createWhereByKey( drivingTable, drivingAlias );
		final String from = createFrom( drivingTable, drivingAlias );

		//now render the joins
		JoinFragment jf = createJoin( tableNumbers, drivingAlias );

		//now render the select clause
		SelectFragment selectFragment = createSelect( columnNumbers, formulaNumbers );

		//now tie it all together
		Select select = new Select( getFactory().getDialect() );
		select.setSelectClause( selectFragment.toFragmentString().substring( 2 ) );
		select.setFromClause( from );
		select.setWhereClause( where );
		select.setOuterJoins( jf.toFromFragmentString(), jf.toWhereFragmentString() );
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			select.setComment( "sequential select " + getEntityName() );
		}
		return select.toStatementString();
	
public voidresetIdentifier(java.lang.Object entity, java.io.Serializable currentId, java.lang.Object currentVersion, org.hibernate.EntityMode entityMode)

		getTuplizer( entityMode ).resetIdentifier( entity, currentId, currentVersion );
	
public final java.lang.StringselectFragment(Joinable rhs, java.lang.String rhsAlias, java.lang.String lhsAlias, java.lang.String entitySuffix, java.lang.String collectionSuffix, boolean includeCollectionColumns)

		return selectFragment( lhsAlias, entitySuffix );
	
public java.lang.StringselectFragment(java.lang.String alias, java.lang.String suffix)

		return identifierSelectFragment( alias, suffix ) +
				propertySelectFragment( alias, suffix, false );
	
public voidsetIdentifier(java.lang.Object object, java.io.Serializable id, org.hibernate.EntityMode entityMode)

		getTuplizer( entityMode ).setIdentifier( object, id );
	
public voidsetPropertyValue(java.lang.Object object, int i, java.lang.Object value, org.hibernate.EntityMode entityMode)

		getTuplizer( entityMode ).setPropertyValue( object, i, value );
	
public voidsetPropertyValue(java.lang.Object object, java.lang.String propertyName, java.lang.Object value, org.hibernate.EntityMode entityMode)

		getTuplizer( entityMode ).setPropertyValue( object, propertyName, value );
	
public voidsetPropertyValues(java.lang.Object object, java.lang.Object[] values, org.hibernate.EntityMode entityMode)

		getTuplizer( entityMode ).setPropertyValues( object, values );
	
public java.lang.String[]toColumns(java.lang.String alias, java.lang.String propertyName)

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

		return propertyMapping.getColumnNames( propertyName );
	
public java.lang.String[]toColumns(java.lang.String name, int i)

		final String alias = generateTableAlias( name, getSubclassPropertyTableNumber( i ) );
		String[] cols = getSubclassPropertyColumnNames( i );
		String[] templates = getSubclassPropertyFormulaTemplateClosure()[i];
		String[] result = new String[cols.length];
		for ( int j = 0; j < cols.length; j++ ) {
			if ( cols[j] == null ) {
				result[j] = StringHelper.replace( templates[j], Template.TEMPLATE, alias );
			}
			else {
				result[j] = StringHelper.qualify( alias, cols[j] );
			}
		}
		return result;
	
public java.lang.StringtoString()

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

		return propertyMapping.toType( propertyName );
	
protected booleanupdate(java.io.Serializable id, java.lang.Object[] fields, java.lang.Object[] oldFields, java.lang.Object rowId, boolean[] includeProperty, int j, java.lang.Object oldVersion, java.lang.Object object, java.lang.String sql, org.hibernate.engine.SessionImplementor session)


		final boolean useVersion = j == 0 && isVersioned();
		final Expectation expectation = Expectations.appropriateExpectation( updateResultCheckStyles[j] );
		final boolean callable = isUpdateCallable( j );
		final boolean useBatch = j == 0 && expectation.canBeBatched() && isBatchable(); //note: updates to joined tables can't be batched...

		if ( log.isTraceEnabled() ) {
			log.trace( "Updating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
			if ( useVersion ) {
				log.trace( "Existing version: " + oldVersion + " -> New version: " + fields[getVersionProperty()] );
			}
		}

		try {

			int index = 1; // starting index
			final PreparedStatement update;
			if ( useBatch ) {
				if ( callable ) {
					update = session.getBatcher().prepareBatchCallableStatement( sql );
				}
				else {
					update = session.getBatcher().prepareBatchStatement( sql );
				}
			}
			else {
				if ( callable ) {
					update = session.getBatcher().prepareCallableStatement( sql );
				}
				else {
					update = session.getBatcher().prepareStatement( sql );
				}
			}

			try {

				index+= expectation.prepare( update );

				//Now write the values of fields onto the prepared statement
				index = dehydrate( id, fields, rowId, includeProperty, propertyColumnUpdateable, j, update, session, index );

				// Write any appropriate versioning conditional parameters
				if ( useVersion && Versioning.OPTIMISTIC_LOCK_VERSION == entityMetamodel.getOptimisticLockMode() ) {
					if ( checkVersion( includeProperty ) ) {
						getVersionType().nullSafeSet( update, oldVersion, index, session );
					}
				}
				else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
					boolean[] versionability = getPropertyVersionability(); //TODO: is this really necessary????
					boolean[] includeOldField = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
							getPropertyUpdateability() : includeProperty;
					Type[] types = getPropertyTypes();
					for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
						boolean include = includeOldField[i] &&
								isPropertyOfTable( i, j ) &&
								versionability[i]; //TODO: is this really necessary????
						if ( include ) {
							boolean[] settable = types[i].toColumnNullness( oldFields[i], getFactory() );
							types[i].nullSafeSet(
									update,
									oldFields[i],
									index,
									settable,
									session
								);
							index += ArrayHelper.countTrue(settable);
						}
					}
				}

				if ( useBatch ) {
					session.getBatcher().addToBatch( expectation );
					return true;
				}
				else {
					return check( update.executeUpdate(), id, j, expectation, update );
				}

			}
			catch ( SQLException sqle ) {
				if ( useBatch ) {
					session.getBatcher().abortBatch( sqle );
				}
				throw sqle;
			}
			finally {
				if ( !useBatch ) {
					session.getBatcher().closeStatement( update );
				}
			}

		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getFactory().getSQLExceptionConverter(),
					sqle,
					"could not update: " + MessageHelper.infoString( this, id, getFactory() ),
					sql
				);
		}
	
public voidupdate(java.io.Serializable id, java.lang.Object[] fields, int[] dirtyFields, boolean hasDirtyCollection, java.lang.Object[] oldFields, java.lang.Object oldVersion, java.lang.Object object, java.lang.Object rowId, org.hibernate.engine.SessionImplementor session)
Update an object


		//note: dirtyFields==null means we had no snapshot, and we couldn't get one using select-before-update
		//	  oldFields==null just means we had no snapshot to begin with (we might have used select-before-update to get the dirtyFields)

		final boolean[] tableUpdateNeeded = getTableUpdateNeeded( dirtyFields, hasDirtyCollection );
		final int span = getTableSpan();

		final boolean[] propsToUpdate;
		final String[] updateStrings;
		if ( entityMetamodel.isDynamicUpdate() && dirtyFields != null ) {
			// For the case of dynamic-update="true", we need to generate the UPDATE SQL
			propsToUpdate = getPropertiesToUpdate( dirtyFields, hasDirtyCollection );
			// don't need to check laziness (dirty checking algorithm handles that)
			updateStrings = new String[span];
			for ( int j = 0; j < span; j++ ) {
				updateStrings[j] = tableUpdateNeeded[j] ?
						generateUpdateString( propsToUpdate, j, oldFields, j == 0 && rowId != null ) :
						null;
			}
		}
		else {
			// For the case of dynamic-update="false", or no snapshot, we use the static SQL
			updateStrings = getUpdateStrings(
					rowId != null,
					hasUninitializedLazyProperties( object, session.getEntityMode() )
				);
			propsToUpdate = getPropertyUpdateability( object, session.getEntityMode() );
		}

		for ( int j = 0; j < span; j++ ) {
			// Now update only the tables with dirty properties (and the table with the version number)
			if ( tableUpdateNeeded[j] ) {
				updateOrInsert(
						id,
						fields,
						oldFields,
						j == 0 ? rowId : null,
						propsToUpdate,
						j,
						oldVersion,
						object,
						updateStrings[j],
						session
					);
			}
		}
	
protected voidupdateOrInsert(java.io.Serializable id, java.lang.Object[] fields, java.lang.Object[] oldFields, java.lang.Object rowId, boolean[] includeProperty, int j, java.lang.Object oldVersion, java.lang.Object object, java.lang.String sql, org.hibernate.engine.SessionImplementor session)
Perform an SQL UPDATE or SQL INSERT


		if ( !isInverseTable( j ) ) {

			final boolean isRowToUpdate;
			if ( isNullableTable( j ) && oldFields != null && isAllNull( oldFields, j ) ) {
				//don't bother trying to update, we know there is no row there yet
				isRowToUpdate = false;
			}
			else if ( isNullableTable( j ) && isAllNull( fields, j ) ) {
				//if all fields are null, we might need to delete existing row
				isRowToUpdate = true;
				delete( id, oldVersion, j, object, getSQLDeleteStrings()[j], session, null );
			}
			else {
				//there is probably a row there, so try to update
				//if no rows were updated, we will find out
				isRowToUpdate = update( id, fields, oldFields, rowId, includeProperty, j, oldVersion, object, sql, session );
			}

			if ( !isRowToUpdate && !isAllNull( fields, j ) ) {
				// assume that the row was not there since it previously had only null
				// values, so do an INSERT instead
				//TODO: does not respect dynamic-insert
				insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
			}

		}

	
protected booleanuseDynamicInsert()

		return entityMetamodel.isDynamicInsert();
	
protected booleanuseDynamicUpdate()

		return entityMetamodel.isDynamicUpdate();
	
protected booleanuseGetGeneratedKeys()

		return getFactory().getSettings().isGetGeneratedKeysEnabled();
	
protected booleanuseInsertSelectIdentity()

		return !useGetGeneratedKeys() && getFactory().getDialect().supportsInsertSelectIdentity();
	
public java.lang.StringwhereJoinFragment(java.lang.String alias, boolean innerJoin, boolean includeSubclasses)

		return getSubclassTableSpan() == 1 ?
				"" : //just a performance opt!
				createJoin( alias, innerJoin, includeSubclasses ).toWhereFragmentString();