⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loadcontexts.cs

📁 NHibernate NET开发者所需的
💻 CS
字号:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using log4net;
using NHibernate.Collection;
using NHibernate.Impl;
using NHibernate.Persister.Collection;
using NHibernate.Util;

namespace NHibernate.Engine.Loading
{	
	/// <summary> 
	/// Maps <see cref="IDataReader"/> to specific contextual data
	/// related to processing that <see cref="IDataReader"/>.
	/// </summary>
	/// <remarks>
	/// Implementation note: internally an <see cref="IdentityMap"/> is used to maintain
	/// the mappings; <see cref="IdentityMap"/> was chosen because I'd rather not be
	/// dependent upon potentially bad <see cref="IDataReader"/> and <see cref="IDataReader"/>
	/// implementations.
	/// Considering the JDBC-redesign work, would further like this contextual info
	/// not mapped separately, but available based on the result set being processed.
	/// This would also allow maintaining a single mapping as we could reliably get
	/// notification of the result-set closing...
	/// </remarks>
	public class LoadContexts
	{
		private static readonly ILog log = LogManager.GetLogger(typeof(LoadContexts));

		[NonSerialized]
		private readonly IPersistenceContext persistenceContext;
		private IDictionary collectionLoadContexts;
		private IDictionary entityLoadContexts;

		private Dictionary<CollectionKey, LoadingCollectionEntry> xrefLoadingCollectionEntries;

		/// <summary> Creates and binds this to the given persistence context. </summary>
		/// <param name="persistenceContext">The persistence context to which this will be bound. </param>
		public LoadContexts(IPersistenceContext persistenceContext)
		{
			this.persistenceContext = persistenceContext;
		}

		/// <summary> 
		/// Retrieves the persistence context to which this is bound.
		/// </summary>
		public IPersistenceContext PersistenceContext
		{
			get { return persistenceContext; }
		}

		private ISessionImplementor Session
		{
			get { return PersistenceContext.Session; }
		}

		internal IDictionary<CollectionKey, LoadingCollectionEntry> LoadingCollectionXRefs
		{
			get { return xrefLoadingCollectionEntries; }
		}

		/// <summary> 
		/// Release internal state associated with the given result set.
		///  </summary>
		/// <param name="resultSet">The result set for which it is ok to release associated resources. </param>
		/// <remarks>
		/// This should be called when we are done with processing said result set,
		/// ideally as the result set is being closed.
		/// </remarks>
		public virtual void Cleanup(IDataReader resultSet)
		{
			if (collectionLoadContexts != null)
			{
				object tempObject;
				tempObject = collectionLoadContexts[resultSet];
				collectionLoadContexts.Remove(resultSet);
				CollectionLoadContext collectionLoadContext = (CollectionLoadContext)tempObject;
				collectionLoadContext.Cleanup();
			}
			if (entityLoadContexts != null)
			{
				object tempObject2;
				tempObject2 = entityLoadContexts[resultSet];
				entityLoadContexts.Remove(resultSet);
				EntityLoadContext entityLoadContext = (EntityLoadContext)tempObject2;
				entityLoadContext.Cleanup();
			}
		}

		/// <summary> Release internal state associated with *all* result sets. </summary>
		/// <remarks>
		/// This is intended as a "failsafe" process to make sure we get everything
		/// cleaned up and released.
		/// </remarks>
		public void Cleanup()
		{
			if (collectionLoadContexts != null)
			{
				foreach (CollectionLoadContext collectionLoadContext in collectionLoadContexts.Values)
				{
					log.Warn("fail-safe cleanup (collections) : " + collectionLoadContext);
					collectionLoadContext.Cleanup();
				}
				collectionLoadContexts.Clear();
			}
			if (entityLoadContexts != null)
			{
				foreach (EntityLoadContext entityLoadContext in entityLoadContexts.Values)
				{
					log.Warn("fail-safe cleanup (entities) : " + entityLoadContext);
					entityLoadContext.Cleanup();
				}
				entityLoadContexts.Clear();
			}
		}

		/// <summary> 
		/// Do we currently have any internal entries corresponding to loading
		/// collections?
		/// </summary>
		/// <returns> True if we currently hold state pertaining to loading collections; false otherwise. </returns>
		public bool HasLoadingCollectionEntries
		{
			get { return (xrefLoadingCollectionEntries != null && !(xrefLoadingCollectionEntries.Count == 0)); }
		}

		/// <summary> 
		/// Get the {@link CollectionLoadContext} associated with the given
		/// {@link ResultSet}, creating one if needed. 
		/// </summary>
		/// <param name="resultSet">The result set for which to retrieve the context. </param>
		/// <returns> The processing context. </returns>
		public CollectionLoadContext GetCollectionLoadContext(IDataReader resultSet)
		{
			CollectionLoadContext context = null;
			if (collectionLoadContexts == null)
			{
				collectionLoadContexts = IdentityMap.Instantiate(8);
			}
			else
			{
				context = (CollectionLoadContext)collectionLoadContexts[resultSet];
			}
			if (context == null)
			{
				if (log.IsDebugEnabled)
				{
					log.Debug("constructing collection load context for result set [" + resultSet + "]");
				}
				context = new CollectionLoadContext(this, resultSet);
				collectionLoadContexts[resultSet] = context;
			}
			return context;
		}

		/// <summary> 
		/// Attempt to locate the loading collection given the owner's key.  The lookup here
		/// occurs against all result-set contexts... 
		/// </summary>
		/// <param name="persister">The collection persister </param>
		/// <param name="ownerKey">The owner key </param>
		/// <returns> The loading collection, or null if not found. </returns>
		public IPersistentCollection LocateLoadingCollection(ICollectionPersister persister, object ownerKey)
		{
			LoadingCollectionEntry lce = LocateLoadingCollectionEntry(new CollectionKey(persister, ownerKey, Session.EntityMode));
			if (lce != null)
			{
				if (log.IsDebugEnabled)
				{
					log.Debug("returning loading collection:" + MessageHelper.InfoString(persister, ownerKey, Session.Factory));
				}
				return lce.Collection;
			}
			else
			{
				// todo : should really move this log statement to CollectionType, where this is used from...
				if (log.IsDebugEnabled)
				{
					log.Debug("creating collection wrapper:" + MessageHelper.InfoString(persister, ownerKey, Session.Factory));
				}
				return null;
			}
		}

		/// <summary> 
		/// Register a loading collection xref. 
		/// </summary>
		/// <param name="entryKey">The xref collection key </param>
		/// <param name="entry">The corresponding loading collection entry </param>
		/// <remarks>
		/// This xref map is used because sometimes a collection is in process of
		/// being loaded from one result set, but needs to be accessed from the
		/// context of another "nested" result set processing.
		/// Implementation note: package protected, as this is meant solely for use
		/// by {@link CollectionLoadContext} to be able to locate collections
		/// being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
		/// </remarks>
		internal void RegisterLoadingCollectionXRef(CollectionKey entryKey, LoadingCollectionEntry entry)
		{
			if (xrefLoadingCollectionEntries == null)
				xrefLoadingCollectionEntries = new Dictionary<CollectionKey, LoadingCollectionEntry>();

			xrefLoadingCollectionEntries[entryKey] = entry;
		}

		/// <summary> 
		/// The inverse of {@link #registerLoadingCollectionXRef}.  Here, we are done
		/// processing the said collection entry, so we remove it from the
		/// load context.
		/// </summary>
		/// <param name="key">The key of the collection we are done processing. </param>
		/// <remarks>
		/// The idea here is that other loading collections can now reference said
		/// collection directly from the {@link PersistenceContext} because it
		/// has completed its load cycle.
		/// Implementation note: package protected, as this is meant solely for use
		/// by {@link CollectionLoadContext} to be able to locate collections
		/// being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
		/// </remarks>
		internal void UnregisterLoadingCollectionXRef(CollectionKey key)
		{
			if (!HasLoadingCollectionEntries)
			{
				return;
			}
			xrefLoadingCollectionEntries.Remove(key);
		}

		/// <summary> 
		/// Locate the LoadingCollectionEntry within *any* of the tracked
		/// <see cref="CollectionLoadContext"/>s.
		/// </summary>
		/// <param name="key">The collection key. </param>
		/// <returns> The located entry; or null. </returns>
		/// <remarks>
		/// Implementation note: package protected, as this is meant solely for use
		/// by <see cref="CollectionLoadContext"/> to be able to locate collections
		/// being loaded by other <see cref="CollectionLoadContext"/>s/ResultSets. 
		/// </remarks>
		internal LoadingCollectionEntry LocateLoadingCollectionEntry(CollectionKey key)
		{
			if (xrefLoadingCollectionEntries == null)
			{
				return null;
			}
			if (log.IsDebugEnabled)
			{
				log.Debug("attempting to locate loading collection entry [" + key + "] in any result-set context");
			}
			LoadingCollectionEntry rtn;
			xrefLoadingCollectionEntries.TryGetValue(key, out rtn);
			if (log.IsDebugEnabled)
			{
				log.Debug(string.Format("collection [{0}] {1} in load context", key, (rtn == null ? "located" : "not located")));
			}
			return rtn;
		}

		internal void CleanupCollectionXRefs(IEnumerable entryKeys)
		{
			foreach (CollectionKey entryKey in entryKeys)
				xrefLoadingCollectionEntries.Remove(entryKey);
		}

		public EntityLoadContext GetEntityLoadContext(IDataReader resultSet)
		{
			EntityLoadContext context = null;
			if (entityLoadContexts == null)
			{
				entityLoadContexts = IdentityMap.Instantiate(8);
			}
			else
			{
				context = (EntityLoadContext)entityLoadContexts[resultSet];
			}
			if (context == null)
			{
				context = new EntityLoadContext(this, resultSet);
				entityLoadContexts[resultSet] = context;
			}
			return context;
		}
	}
}

⌨️ 快捷键说明

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