loader.java

来自「hibernate-3.0.5 中文文档」· Java 代码 · 共 1,696 行 · 第 1/4 页

JAVA
1,696
字号
				}							}			if ( log.isTraceEnabled() ) log.trace( "done processing result set (" + count + " rows)" );		}		finally {			session.getBatcher().closeQueryStatement( st, rs );		}		initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly() );		if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );		return results; //getResultList(results);	}	protected boolean isSubselectLoadingEnabled() {		return false;	}		protected boolean hasSubselectLoadableCollections() {		final Loadable[] loadables = getEntityPersisters();		for (int i=0; i<loadables.length; i++ ) {			if ( loadables[i].hasSubselectLoadableCollections() ) return true;		}		return false;	}		private static Set[] transpose( List keys ) {		Set[] result = new Set[ ( ( EntityKey[] ) keys.get(0) ).length ];		for ( int j=0; j<result.length; j++ ) {			result[j] = new HashSet( keys.size() );			for ( int i=0; i<keys.size(); i++ ) {				result[j].add( ( ( EntityKey[] ) keys.get(i) ) [j] );			}		}		return result;	}	private void createSubselects(List keys, QueryParameters queryParameters, SessionImplementor session) {		if ( keys.size() > 1 ) { //if we only returned one entity, query by key is more efficient						Set[] keySets = transpose(keys);						final Loadable[] loadables = getEntityPersisters();			final String[] aliases = getAliases();			final Iterator iter = keys.iterator();			while ( iter.hasNext() ) {								final EntityKey[] rowKeys = (EntityKey[]) iter.next();				for ( int i=0; i<rowKeys.length; i++ ) {										if ( rowKeys[i]!=null && loadables[i].hasSubselectLoadableCollections() ) {												SubselectFetch subselectFetch = new SubselectFetch( 								//getSQLString(), 								aliases[i], 								loadables[i], 								queryParameters, 								keySets[i] 							);												session.getPersistenceContext()							.getBatchFetchQueue()							.addSubselect( rowKeys[i], subselectFetch );					}									}							}		}	}	private void initializeEntitiesAndCollections(			final List hydratedObjects,			final Object resultSetId,			final SessionImplementor session,			final boolean readOnly) 	throws HibernateException {				//important: reuse the same event instances for performance!		final PreLoadEvent pre = new PreLoadEvent(session);		final PostLoadEvent post = new PostLoadEvent(session);				final CollectionPersister[] collectionPersisters = getCollectionPersisters();		if ( collectionPersisters != null ) {			for ( int i=0; i<collectionPersisters.length; i++ ) {				if ( collectionPersisters[i].isArray() ) {					//for arrays, we should end the collection load before resolving					//the entities, since the actual array instances are not instantiated					//during loading					//TODO: or we could do this polymorphically, and have two					//      different operations implemented differently for arrays					endCollectionLoad( resultSetId, session, collectionPersisters[i] );				}			}		}		if ( getEntityPersisters().length > 0 ) { //if no persisters, hydratedObjects is null			int hydratedObjectsSize = hydratedObjects.size();			if ( log.isTraceEnabled() ) log.trace( "total objects hydrated: " + hydratedObjectsSize );			for ( int i = 0; i < hydratedObjectsSize; i++ ) {				TwoPhaseLoad.initializeEntity( hydratedObjects.get(i), readOnly, session, pre, post );			}		}				if ( collectionPersisters != null ) {			for ( int i=0; i<collectionPersisters.length; i++ ) {				if ( !collectionPersisters[i].isArray() ) {					//for sets, we should end the collection load after resolving					//the entities, since we might call hashCode() on the elements					//TODO: or we could do this polymorphically, and have two					//      different operations implemented differently for arrays					endCollectionLoad( resultSetId, session, collectionPersisters[i] );				}			}		}			}	private void endCollectionLoad(			final Object resultSetId, 			final SessionImplementor session, 			final CollectionPersister collectionPersister	) {		//this is a query and we are loading multiple instances of the same collection role		session.getPersistenceContext().getCollectionLoadContext()			.endLoadingCollections( collectionPersister, resultSetId, session );	}	protected List getResultList(List results) throws QueryException {		return results;	}	/**	 * Get the actual object that is returned in the user-visible result list.	 * This empty implementation merely returns its first argument. This is	 * overridden by some subclasses.	 */	protected Object getResultColumnOrRow(Object[] row, ResultSet rs, SessionImplementor session)			throws SQLException, HibernateException {		return row;	}	/**	 * For missing objects associated by one-to-one with another object in the	 * result set, register the fact that the the object is missing with the	 * session.	 */	private void registerNonExists(final EntityKey[] keys,								   final Loadable[] persisters,								   final SessionImplementor session) {				final int[] owners = getOwners();		if ( owners != null ) {						EntityType[] ownerAssociationTypes = getOwnerAssociationTypes();			for ( int i = 0; i < keys.length; i++ ) {								int owner = owners[i];				if ( owner > -1 ) {					EntityKey ownerKey = keys[owner];					if ( keys[i] == null && ownerKey != null ) {												final PersistenceContext persistenceContext = session.getPersistenceContext();												/*final boolean isPrimaryKey;						final boolean isSpecialOneToOne;						if ( ownerAssociationTypes == null || ownerAssociationTypes[i] == null ) {							isPrimaryKey = true;							isSpecialOneToOne = false;						}						else {							isPrimaryKey = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName()==null;							isSpecialOneToOne = ownerAssociationTypes[i].getLHSPropertyName()!=null;						}*/												//TODO: can we *always* use the "null property" approach for everything?						/*if ( isPrimaryKey && !isSpecialOneToOne ) {							persistenceContext.addNonExistantEntityKey( 									new EntityKey( ownerKey.getIdentifier(), persisters[i], session.getEntityMode() ) 							);						}						else if ( isSpecialOneToOne ) {*/						boolean isOneToOneAssociation = ownerAssociationTypes!=null && 								ownerAssociationTypes[i]!=null && 								ownerAssociationTypes[i].isOneToOne();						if ( isOneToOneAssociation ) {							persistenceContext.addNullProperty( ownerKey, 									ownerAssociationTypes[i].getPropertyName() );						}						/*}						else {							persistenceContext.addNonExistantEntityUniqueKey( new EntityUniqueKey( 									persisters[i].getEntityName(),									ownerAssociationTypes[i].getRHSUniqueKeyPropertyName(),									ownerKey.getIdentifier(),									persisters[owner].getIdentifierType(),									session.getEntityMode()							) );						}*/					}				}			}		}	}	/**	 * Read one collection element from the current row of the JDBC result set	 */	private void readCollectionElement(final Object optionalOwner,									   final Serializable optionalKey,									   final CollectionPersister persister,	                                   final CollectionAliases descriptor,									   final ResultSet rs,									   final SessionImplementor session)			throws HibernateException, SQLException {		final PersistenceContext persistenceContext = session.getPersistenceContext();		final Serializable collectionRowKey = (Serializable) persister.readKey( rs, descriptor.getSuffixedKeyAliases(), session );				if ( collectionRowKey != null ) {			// we found a collection element in the result set			if ( log.isDebugEnabled() ) {				log.debug( "found row of collection: " +						MessageHelper.collectionInfoString( persister, collectionRowKey, getFactory() ) );			}			Object owner = optionalOwner;			if ( owner == null ) {				owner = persistenceContext.getCollectionOwner( collectionRowKey, persister );				if ( owner == null ) {					//TODO: This is assertion is disabled because there is a bug that means the					//	  original owner of a transient, uninitialized collection is not known					//	  if the collection is re-referenced by a different object associated					//	  with the current Session					//throw new AssertionFailure("bug loading unowned collection");				}			}			PersistentCollection rowCollection = persistenceContext.getCollectionLoadContext()			        .getLoadingCollection( persister, collectionRowKey, rs, session.getEntityMode() );			if ( rowCollection != null ) {				rowCollection.readFrom( rs, persister, descriptor, owner );			}		}		else if ( optionalKey != null ) {			// we did not find a collection element in the result set, so we			// ensure that a collection is created with the owner's identifier,			// since what we have is an empty collection			if ( log.isDebugEnabled() ) {				log.debug( "result set contains (possibly empty) collection: " +						MessageHelper.collectionInfoString( persister, optionalKey, getFactory() ) );			}			persistenceContext.getCollectionLoadContext()				.getLoadingCollection( persister, optionalKey, rs, session.getEntityMode() ); //handle empty collection		}		// else no collection element, but also no owner	}	/**	 * If this is a collection initializer, we need to tell the session that a collection	 * is being initilized, to account for the possibility of the collection having	 * no elements (hence no rows in the result set).	 */	private void handleEmptyCollections(final Serializable[] keys,										final Object resultSetId,										final SessionImplementor session)			throws HibernateException {		if ( keys != null ) {			// this is a collection initializer, so we must create a collection			// for each of the passed-in keys, to account for the possibility			// that the collection is empty and has no rows in the result set			CollectionPersister[] collectionPersisters = getCollectionPersisters();			for ( int j=0; j<collectionPersisters.length; j++ ) {				for ( int i = 0; i < keys.length; i++ ) {					//handle empty collections						if ( log.isDebugEnabled() ) {						log.debug( "result set contains (possibly empty) collection: " +								MessageHelper.collectionInfoString( collectionPersisters[j], keys[i], getFactory() ) );					}						session.getPersistenceContext()						.getCollectionLoadContext()						.getLoadingCollection( collectionPersisters[j], keys[i], resultSetId, session.getEntityMode() );				}			}		}		// else this is not a collection initializer (and empty collections will		// be detected by looking for the owner's identifier in the result set)	}	/**	 * Read a row of <tt>Key</tt>s from the <tt>ResultSet</tt> into the given array.	 * Warning: this method is side-effecty.	 * <p/>	 * If an <tt>id</tt> is given, don't bother going to the <tt>ResultSet</tt>.	 */	private EntityKey getKeyFromResultSet(final int i,										  final Loadable persister,										  final Serializable id,										  final ResultSet rs,										  final SessionImplementor session)			throws HibernateException, SQLException {		Serializable resultId;		// if we know there is exactly 1 row, we can skip.		// it would be great if we could _always_ skip this;		// it is a problem for <key-many-to-one>		if ( isSingleRowLoader() && id != null ) {			resultId = id;		}		else {						Type idType = persister.getIdentifierType();			resultId = (Serializable) idType.nullSafeGet(					rs,					getEntityAliases()[i].getSuffixedKeyAliases(),					session,					null //problematic for <key-many-to-one>!			);						final boolean idIsResultId = id != null && 					resultId != null && 					idType.isEqual( id, resultId, session.getEntityMode(), factory );						if ( idIsResultId ) resultId = id; //use the id passed in		}		return resultId == null ?				null :				new EntityKey( resultId, persister, session.getEntityMode() );	}	/**	 * Check the version of the object in the <tt>ResultSet</tt> against	 * the object version in the session cache, throwing an exception	 * if the version numbers are different	 */	private void checkVersion(final int i,							  final Loadable persister,							  final Serializable id,							  final Object entity,							  final ResultSet rs,							  final SessionImplementor session)			throws HibernateException, SQLException {		Object version = session.getPersistenceContext().getEntry( entity ).getVersion();		if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet			VersionType versionType = persister.getVersionType();			Object currentVersion = versionType.nullSafeGet(					rs,					getEntityAliases()[i].getSuffixedVersionAliases(),					session,					null			);			if ( !versionType.isEqual(version, currentVersion) ) {				throw new StaleObjectStateException( persister.getEntityName(), id );			}		}	}	/**	 * Resolve any ids for currently loaded objects, duplications within the	 * <tt>ResultSet</tt>, etc. Instantiate empty objects to be initialized from the	 * <tt>ResultSet</tt>. Return an array of objects (a row of results) and an	 * array of booleans (by side-effect) that determine whether the corresponding	 * object should be initialized.	 */	private Object[] getRow(final ResultSet rs,							final Loadable[] persisters,							final EntityKey[] keys,							final Object optionalObject,							final EntityKey optionalObjectKey,							final LockMode[] lockModes,							final List hydratedObjects,							final SessionImplementor session)			throws HibernateException, SQLException {		final int cols = persisters.length;		final EntityAliases[] descriptors = getEntityAliases();		if ( log.isDebugEnabled() ) log.debug( "result row: " + StringHelper.toString( keys ) );		final Object[] rowResults = new Object[cols];		for ( int i = 0; i < cols; i++ ) {			Object object = null;			EntityKey key = keys[i];			if ( keys[i] == null ) {				//do nothing			}			else {				//If the object is already loaded, return the loaded one				object = session.getEntityUsingInterceptor( key );				if ( object != null ) {					//its already loaded so don't need to hydrate it					instanceAlreadyLoaded( rs,							i,							persisters[i],

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?