📄 loader.java
字号:
} 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 EntityKey[][] transpose( EntityKey[][] keys ) { EntityKey[][] result = new EntityKey[ keys[0].length ][]; for ( int j=0; j<result.length; j++ ) { result[j] = new EntityKey[keys.length]; for ( int i=0; i<keys.length; i++ ) { result[j][i] = keys[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 //TODO: remove unnecessary creation of outer array EntityKey[][] keyArray = transpose( ( EntityKey[][] ) keys.toArray( new EntityKey[ keys.size() ][] ) ); 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, keyArray[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); 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 ); } } final CollectionPersister collectionPersister = getCollectionPersister(); if ( collectionPersister != null ) { //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 ) { AssociationType[] 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 ) { persistenceContext.addNullProperty( ownerKey, ownerAssociationTypes[i].getLHSPropertyName() ); } 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 ResultSet rs, final SessionImplementor session) throws HibernateException, SQLException { final CollectionPersister collectionPersister = getCollectionPersister(); final Serializable collectionRowKey = ( Serializable ) collectionPersister.readKey( rs, session ); final PersistenceContext persistenceContext = session.getPersistenceContext(); if ( collectionRowKey != null ) { // we found a collection element in the result set if ( log.isDebugEnabled() ) { log.debug( "found row of collection: " + MessageHelper.collectionInfoString( collectionPersister, collectionRowKey, getFactory() ) ); } Object owner = optionalOwner; if ( owner == null ) { owner = persistenceContext.getCollectionOwner( collectionRowKey, collectionPersister ); 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( collectionPersister, collectionRowKey, rs, session.getEntityMode() ); if ( rowCollection != null ) rowCollection.readFrom( rs, collectionPersister, 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( collectionPersister, optionalKey, getFactory() ) ); } persistenceContext.getCollectionLoadContext() .getLoadingCollection( collectionPersister, 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 collectionPersister = getCollectionPersister(); for ( int i = 0; i < keys.length; i++ ) { //handle empty collections if ( log.isDebugEnabled() ) { log.debug( "result set contains (possibly empty) collection: " + MessageHelper.collectionInfoString( collectionPersister, keys[i], getFactory() ) ); } session.getPersistenceContext() .getCollectionLoadContext() .getLoadingCollection( collectionPersister, 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 ); //TODO: should it be getSessionEntity() ? if ( object != null ) { //its already loaded so don't need to hydrate it instanceAlreadyLoaded( rs, i, persisters[i], key, object, lockModes[i], session ); } else { object = instanceNotYetLoaded( rs, i, persisters[i], descriptors[i].getRowIdAlias(), key, lockModes[i], optionalObjectKey, optionalObject, hydratedObjects, session ); } } rowResults[i] = object; } return rowResults; } /** * The entity instance is already in the session cache
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -