FileDocCategorySizeDatePackage
OneToManyPersister.javaAPI DocHibernate 3.2.511423Thu Jun 22 14:51:44 BST 2006org.hibernate.persister.collection

OneToManyPersister

public class OneToManyPersister extends AbstractCollectionPersister
Collection persister for one-to-many associations.
author
Gavin King

Fields Summary
private final boolean
cascadeDeleteEnabled
private final boolean
keyIsNullable
private final boolean
keyIsUpdateable
Constructors Summary
public OneToManyPersister(org.hibernate.mapping.Collection collection, org.hibernate.cache.CacheConcurrencyStrategy cache, org.hibernate.cfg.Configuration cfg, org.hibernate.engine.SessionFactoryImplementor factory)

		super( collection, cache, cfg, factory );
		cascadeDeleteEnabled = collection.getKey().isCascadeDeleteEnabled() &&
				factory.getDialect().supportsCascadeDelete();
		keyIsNullable = collection.getKey().isNullable();
		keyIsUpdateable = collection.getKey().isUpdateable();
	
Methods Summary
public booleanconsumesCollectionAlias()

		return true;
	
public booleanconsumesEntityAlias()

		return true;
	
protected org.hibernate.loader.collection.CollectionInitializercreateCollectionInitializer(java.util.Map enabledFilters)
Create the OneToManyLoader

see
org.hibernate.loader.collection.OneToManyLoader

		return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), enabledFilters );
	
protected org.hibernate.loader.collection.CollectionInitializercreateSubselectInitializer(org.hibernate.engine.SubselectFetch subselect, org.hibernate.engine.SessionImplementor session)

		return new SubselectOneToManyLoader( 
				this,
				subselect.toSubselectString( getCollectionType().getLHSPropertyName() ),
				subselect.getResult(),
				subselect.getQueryParameters(),
				subselect.getNamedParameterLocMap(),
				session.getFactory(),
				session.getEnabledFilters() 
			);
	
protected intdoUpdateRows(java.io.Serializable id, org.hibernate.collection.PersistentCollection collection, org.hibernate.engine.SessionImplementor session)


		// we finish all the "removes" first to take care of possible unique
		// constraints and so that we can take better advantage of batching
		
		try {
			int count = 0;
			if ( isRowDeleteEnabled() ) {
				boolean useBatch = true;
				PreparedStatement st = null;
				// update removed rows fks to null
				try {
					int i = 0;
	
					Iterator entries = collection.entries( this );
					int offset = 1;
					Expectation expectation = Expectations.NONE;
					while ( entries.hasNext() ) {
	
						Object entry = entries.next();
						if ( collection.needsUpdating( entry, i, elementType ) ) {  // will still be issued when it used to be null
							if ( st == null ) {
								String sql = getSQLDeleteRowString();
								if ( isDeleteCallable() ) {
									expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() );
									useBatch = expectation.canBeBatched();
									st = useBatch
											? session.getBatcher().prepareBatchCallableStatement( sql )
								            : session.getBatcher().prepareCallableStatement( sql );
									offset += expectation.prepare( st );
								}
								else {
									st = session.getBatcher().prepareBatchStatement( getSQLDeleteRowString() );
								}
							}
							int loc = writeKey( st, id, offset, session );
							writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session );
							if ( useBatch ) {
								session.getBatcher().addToBatch( expectation );
							}
							else {
								expectation.verifyOutcome( st.executeUpdate(), st, -1 );
							}
							count++;
						}
						i++;
					}
				}
				catch ( SQLException sqle ) {
					if ( useBatch ) {
						session.getBatcher().abortBatch( sqle );
					}
					throw sqle;
				}
				finally {
					if ( !useBatch ) {
						session.getBatcher().closeStatement( st );
					}
				}
			}
			
			if ( isRowInsertEnabled() ) {
				Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() );
				boolean callable = isInsertCallable();
				boolean useBatch = expectation.canBeBatched();
				String sql = getSQLInsertRowString();
				PreparedStatement st = null;
				// now update all changed or added rows fks
				try {
					int i = 0;
					Iterator entries = collection.entries( this );
					while ( entries.hasNext() ) {
						Object entry = entries.next();
						int offset = 1;
						if ( collection.needsUpdating( entry, i, elementType ) ) {
							if ( useBatch ) {
								if ( st == null ) {
									if ( callable ) {
										st = session.getBatcher().prepareBatchCallableStatement( sql );
									}
									else {
										st = session.getBatcher().prepareBatchStatement( sql );
									}
								}
							}
							else {
								if ( callable ) {
									st = session.getBatcher().prepareCallableStatement( sql );
								}
								else {
									st = session.getBatcher().prepareStatement( sql );
								}
							}

							offset += expectation.prepare( st );

							int loc = writeKey( st, id, offset, session );
							if ( hasIndex && !indexContainsFormula ) {
								loc = writeIndexToWhere( st, collection.getIndex( entry, i, this ), loc, session );
							}

							writeElementToWhere( st, collection.getElement( entry ), loc, session );

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

			return count;
		}
		catch ( SQLException sqle ) {
			throw JDBCExceptionHelper.convert(
					getSQLExceptionConverter(),
					sqle,
					"could not update collection rows: " + 
					MessageHelper.collectionInfoString( this, id, getFactory() ),
					getSQLInsertRowString()
			);
		}
	
public java.lang.StringfilterFragment(java.lang.String alias)

		String result = super.filterFragment( alias );
		if ( getElementPersister() instanceof Joinable ) {
			result += ( ( Joinable ) getElementPersister() ).oneToManyFilterFragment( alias );
		}
		return result;

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

		return ( ( Joinable ) getElementPersister() ).fromJoinFragment( alias, innerJoin, includeSubclasses );
	
protected java.lang.StringgenerateDeleteRowString()
Generate the SQL UPDATE that updates a particular row's foreign key to null

		
		Update update = new Update( getDialect() )
				.setTableName( qualifiedTableName )
				.addColumns( keyColumnNames, "null" );
		
		if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" );
		
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			update.setComment( "delete one-to-many row " + getRole() );
		}
		
		//use a combination of foreign key columns and pk columns, since
		//the ordering of removal and addition is not guaranteed when
		//a child moves from one parent to another
		String[] rowSelectColumnNames = ArrayHelper.join(keyColumnNames, elementColumnNames);
		return update.setPrimaryKeyColumnNames( rowSelectColumnNames )
				.toStatementString();
	
protected java.lang.StringgenerateDeleteString()
Generate the SQL UPDATE that updates all the foreign keys to null

		
		Update update = new Update( getDialect() )
				.setTableName( qualifiedTableName )
				.addColumns( keyColumnNames, "null" )
				.setPrimaryKeyColumnNames( keyColumnNames );
		
		if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" );
		
		if ( hasWhere ) update.setWhere( sqlWhereString );
		
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			update.setComment( "delete one-to-many " + getRole() );
		}
		
		return update.toStatementString();
	
protected java.lang.StringgenerateInsertRowString()
Generate the SQL UPDATE that updates a foreign key to a value

		
		Update update = new Update( getDialect() )
				.setTableName( qualifiedTableName )
				.addColumns( keyColumnNames );
		
		if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames );
		
		//identifier collections not supported for 1-to-many
		if ( getFactory().getSettings().isCommentsEnabled() ) {
			update.setComment( "create one-to-many row " + getRole() );
		}
		
		return update.setPrimaryKeyColumnNames( elementColumnNames )
				.toStatementString();
	
protected java.lang.StringgenerateUpdateRowString()
Not needed for one-to-many association

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

		return new CollectionElementLoader( this, getFactory(), session.getEnabledFilters() )
				.loadElement( session, key, incrementIndexByBase(index) );
	
public java.lang.StringgetTableName()

		return ( ( Joinable ) getElementPersister() ).getTableName();
	
public booleanisCascadeDeleteEnabled()

		return cascadeDeleteEnabled;
	
public booleanisManyToMany()

		return false;
	
public booleanisOneToMany()

		return true;
	
protected booleanisRowDeleteEnabled()

		return keyIsUpdateable && keyIsNullable;
	
protected booleanisRowInsertEnabled()

		return keyIsUpdateable;
	
public java.lang.StringselectFragment(org.hibernate.persister.entity.Joinable rhs, java.lang.String rhsAlias, java.lang.String lhsAlias, java.lang.String entitySuffix, java.lang.String collectionSuffix, boolean includeCollectionColumns)

		StringBuffer buf = new StringBuffer();
		if ( includeCollectionColumns ) {
//			buf.append( selectFragment( lhsAlias, "" ) )//ignore suffix for collection columns!
			buf.append( selectFragment( lhsAlias, collectionSuffix ) )
					.append( ", " );
		}
		OuterJoinLoadable ojl = ( OuterJoinLoadable ) getElementPersister();
		return buf.append( ojl.selectFragment( lhsAlias, entitySuffix ) )//use suffix for the entity columns
				.toString();
	
public java.lang.StringwhereJoinFragment(java.lang.String alias, boolean innerJoin, boolean includeSubclasses)

		return ( ( Joinable ) getElementPersister() ).whereJoinFragment( alias, innerJoin, includeSubclasses );