/// <summary> /// Retrieve the collection that is being loaded as part of processing this result set. /// </summary> /// <param name="persister">The persister for the collection being requested. </param> /// <param name="key">The key of the collection being requested. </param> /// <returns> The loading collection (see discussion above). </returns> /// <remarks> /// Basically, there are two valid return values from this method:<ul> /// <li>an instance of {@link PersistentCollection} which indicates to /// continue loading the result set row data into that returned collection /// instance; this may be either an instance already associated and in the /// midst of being loaded, or a newly instantiated instance as a matching /// associated collection was not found.</li> /// <li><i>null</i> indicates to ignore the corresponding result set row /// data relating to the requested collection; this indicates that either /// the collection was found to already be associated with the persistence /// context in a fully loaded state, or it was found in a loading state /// associated with another result set processing context.</li> /// </ul> /// </remarks> public IPersistentCollection GetLoadingCollection(ICollectionPersister persister, object key) { CollectionKey collectionKey = new CollectionKey(persister, key); if (log.IsDebugEnabled()) { log.Debug("starting attempt to find loading collection [{0}]", MessageHelper.InfoString(persister.Role, key)); } LoadingCollectionEntry loadingCollectionEntry = loadContexts.LocateLoadingCollectionEntry(collectionKey); if (loadingCollectionEntry == null) { // look for existing collection as part of the persistence context IPersistentCollection collection = loadContexts.PersistenceContext.GetCollection(collectionKey); if (collection != null) { if (collection.WasInitialized) { log.Debug("collection already initialized; ignoring"); return(null); // ignore this row of results! Note the early exit } else { // initialize this collection log.Debug("collection not yet initialized; initializing"); } } else { object owner = loadContexts.PersistenceContext.GetCollectionOwner(key, persister); bool newlySavedEntity = owner != null && loadContexts.PersistenceContext.GetEntry(owner).Status != Status.Loading; if (newlySavedEntity) { // important, to account for newly saved entities in query // todo : some kind of check for new status... log.Debug("owning entity already loaded; ignoring"); return(null); } else { // create one if (log.IsDebugEnabled()) { // Do not log the resultSet as-is, it is an IEnumerable which may get enumerated by loggers. // (Serilog does that.) See #1667. log.Debug("instantiating new collection [key={0}, rs={1}]", key, resultSet.GetType()); } collection = persister.CollectionType.Instantiate(loadContexts.PersistenceContext.Session, persister, key); } } collection.BeforeInitialize(persister, -1); collection.BeginRead(); localLoadingCollectionKeys.Add(collectionKey); loadContexts.RegisterLoadingCollectionXRef(collectionKey, new LoadingCollectionEntry(resultSet, persister, key, collection)); return(collection); } else { if (loadingCollectionEntry.ResultSet == resultSet) { log.Debug("found loading collection bound to current result set processing; reading row"); return(loadingCollectionEntry.Collection); } else { // ignore this row, the collection is in process of // being loaded somewhere further "up" the stack log.Debug("collection is already being initialized; ignoring row"); return(null); } } }