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

📄 persistentgenericbag.cs

📁 NHibernate NET开发者所需的
💻 CS
字号:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using NHibernate.DebugHelpers;
using NHibernate.Engine;
using NHibernate.Loader;
using NHibernate.Persister.Collection;
using NHibernate.Type;

namespace NHibernate.Collection.Generic
{
	/// <summary>
	/// An unordered, unkeyed collection that can contain the same element
	/// multiple times. The .NET collections API, has no <c>Bag</c>.
	/// The <see cref="ICollection{T}" /> interface closely resembles bag semantics,
	/// however NHibernate for .NET 1.1 used <see cref="System.Collections.IList"/> so 
	/// <see cref="IList{T}"/> is used to ensure the easiest transition
	/// to generics.
	/// </summary>
	/// <typeparam name="T">The type of the element the bag should hold.</typeparam>
	/// <remarks>The underlying collection used is an <see cref="List{T}"/></remarks>
	[Serializable]
	[DebuggerTypeProxy(typeof(CollectionProxy<>))]
	public class PersistentGenericBag<T> : AbstractPersistentCollection, IList<T>, IList
	{
		private IList<T> bag;

		/// <summary>
		/// Initializes an instance of the <see cref="PersistentGenericBag{T}"/>
		/// in the <paramref name="session"/>.
		/// </summary>
		/// <param name="session">The <see cref="ISessionImplementor"/> the bag is in.</param>
		public PersistentGenericBag(ISessionImplementor session)
			: base(session)
		{
		}

		/// <summary>
		/// Initializes an instance of the <see cref="PersistentGenericBag{T}"/>
		/// that wraps an existing <see cref="IList{T}"/> in the <paramref name="session"/>.
		/// </summary>
		/// <param name="session">The <see cref="ISessionImplementor"/> the bag is in.</param>
		/// <param name="coll">The <see cref="IList{T}"/> to wrap.</param>
		public PersistentGenericBag(ISessionImplementor session, IList<T> coll)
			: base(session)
		{
			bag = coll;

			if (bag == null)
			{
				bag = new List<T>();
				((List<T>) bag).AddRange(coll);
			}
			SetInitialized();
			IsDirectlyAccessible = true;
		}

		#region ICollection<T> Members

		public void Add(T item)
		{
			if (!QueueAdd(item))
			{
				Write();
				bag.Add(item);
			}
		}

		public void Clear()
		{
			Initialize(true);
			if (bag.Count > 0)
			{
				Dirty();
				bag.Clear();
			}
		}

		public bool Contains(T item)
		{
			Read();
			return bag.Contains(item);
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			Read();
			bag.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get
			{
				Read();
				return bag.Count;
			}
		}

		bool ICollection<T>.IsReadOnly
		{
			get { return false; }
		}

		public bool Remove(T item)
		{
			Initialize(true);
			return MakeDirtyIfTrue(bag.Remove(item));
		}

		#endregion

		#region IList<T> Members

		public int IndexOf(T item)
		{
			Read();
			return bag.IndexOf(item);
		}

		public void Insert(int index, T item)
		{
			Initialize(true);
			bag.Insert(index, item);
			Dirty();
		}

		public void RemoveAt(int index)
		{
			Initialize(true);
			bag.RemoveAt(index);
			Dirty();
		}

		public T this[int index]
		{
			get
			{
				Read();
				return bag[index];
			}
			set
			{
				Write();
				bag[index] = value;
			}
		}

		#endregion

		#region IEnumerable<T> Members

		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			Read();
			return bag.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			Read();
			return bag.GetEnumerator();
		}

		#endregion

		#region AbstractPersistentCollection Members

		/// <summary>
		/// Is the initialized GenericBag empty?
		/// </summary>
		/// <value><see langword="true" /> if the bag has a Count==0, <see langword="false" /> otherwise.</value>
		public override bool Empty
		{
			get { return bag.Count == 0; }
		}

		public override void InitializeFromCache(ICollectionPersister persister, object disassembled, object owner)
		{
			BeforeInitialize(persister);
			object[] array = (object[]) disassembled;
			for (int i = 0; i < array.Length; i++)
			{
				bag.Add((T) persister.ElementType.Assemble(array[i], Session, owner));
			}
			SetInitialized();
		}

		/// <summary>
		/// Gets a <see cref="Boolean"/> indicating if this Bag needs to be recreated
		/// in the database.
		/// </summary>
		/// <param name="persister">The <see cref="ICollectionPersister"/> for this Collection.</param>
		/// <returns>
		/// <see langword="false" /> if this is a <c>one-to-many</c> bag, <see langword="true" /> if this is not
		/// a <c>one-to-many</c> bag.  Since a bag is an unordered, unindexed collection 
		/// that permits duplicates it is not possible to determine what has changed in a
		/// <c>many-to-many</c> so it is just recreated.
		/// </returns>
		public override bool NeedsRecreate(ICollectionPersister persister)
		{
			return !persister.IsOneToMany;
		}

		public override IEnumerable Entries()
		{
			return bag;
		}

		public override object ReadFrom(IDataReader reader, ICollectionPersister persister, ICollectionAliases descriptor,
		                                object owner)
		{
			object element = persister.ReadElement(reader, owner, descriptor.SuffixedElementAliases, Session);
			// TODO: to make this more net-2.0 friendly the value returned from persister.ReadElement
			// should be specified by a type parameter.  However, that would really break NH with net-1.1
			// and I don't want to do that yet - so the cast is appropriate.
			bag.Add((T) element);
			return element;
		}

		//		public override void WriteTo(IDbCommand st, ICollectionPersister persister, object entry, int i, bool writeOrder)
		//		{
		//			persister.WriteElement(st, entry, writeOrder, Session);
		//		}

		public override object GetIndex(object entry, int i)
		{
			throw new NotSupportedException("Bags don't have indexes");
		}

		public override object GetElement(object entry)
		{
			return entry;
		}

		public override object GetSnapshotElement(object entry, int i)
		{
			IList<T> sn = (IList<T>) GetSnapshot();
			return sn[i];
		}

		public override void BeforeInitialize(ICollectionPersister persister)
		{
			this.bag = (IList<T>) persister.CollectionType.Instantiate(-1);
		}

		public override bool EqualsSnapshot(ICollectionPersister persister)
		{
			IType elementType = persister.ElementType;
			IList<T> sn = (IList<T>)GetSnapshot();
			if (sn.Count != bag.Count)
			{
				return false;
			}

			foreach (T elt in bag)
			{
				if (CountOccurrences(elt, bag, elementType) != CountOccurrences(elt, sn, elementType))
				{
					return false;
				}
			}

			return true;
		}

		/// <summary>
		/// Counts the number of times that the <paramref name="element"/> occurs
		/// in the <paramref name="list"/>.
		/// </summary>
		/// <param name="element">The element to find in the list.</param>
		/// <param name="list">The <see cref="ICollection{T}"/> to search.</param>
		/// <param name="elementType">The <see cref="IType"/> that can determine equality.</param>
		/// <returns>
		/// The number of occurrences of the element in the list.
		/// </returns>
		private int CountOccurrences(T element, ICollection<T> list, IType elementType)
		{
			int result = 0;
			foreach (T obj in list)
			{
				if (elementType.IsEqual(element, obj, EntityMode.Poco))
				{
					result++;
				}
			}

			return result;
		}

		protected override ICollection Snapshot(ICollectionPersister persister)
		{
			List<T> clonedList = new List<T>();
			foreach (T obj in bag)
			{
				clonedList.Add((T) persister.ElementType.DeepCopy(obj, EntityMode.Poco, persister.Factory));
			}

			return clonedList;
		}

		public override object Disassemble(ICollectionPersister persister)
		{
			int length = bag.Count;
			object[] result = new object[length];

			int i = 0;
			foreach (T item in bag)
			{
				result[i] = persister.ElementType.Disassemble(item, Session, null);
				i++;
			}

			return result;
		}

		public override bool EntryExists(object entry, int i)
		{
			return entry != null;
		}

		public override bool NeedsInserting(object entry, int i, IType elemType)
		{
			IList sn = (IList) GetSnapshot();
			if (sn.Count > i && elemType.IsEqual(sn[i], entry, EntityMode.Poco))
			{
				// a shortcut if its location didn't change
				return false;
			}
			else
			{
				//search for it
				foreach (object oldObject in sn)
				{
					if (elemType.IsEqual(oldObject, entry, EntityMode.Poco))
					{
						return false;
					}
				}
				return true;
			}
		}

		public override bool NeedsUpdating(object entry, int i, IType elemType)
		{
			return false;
		}

		public override IEnumerable GetDeletes(IType elemType, bool indexIsFormula)
		{
			ArrayList deletes = new ArrayList();
			IList sn = (IList) GetSnapshot();

			int i = 0;

			foreach (object oldObject in sn)
			{
				bool found = false;
				if (bag.Count > i && elemType.IsEqual(oldObject, bag[i++], EntityMode.Poco))
				{
					//a shortcut if its location didn't change!
					found = true;
				}
				else
				{
					//search for it
					foreach (object newObject in bag)
					{
						if (elemType.IsEqual(oldObject, newObject, EntityMode.Poco))
						{
							found = true;
							break;
						}
					}
				}
				if (!found)
				{
					deletes.Add(oldObject);
				}
			}

			return deletes;
		}

		/// <summary>
		/// Is this the wrapper for the given underlying bag instance?
		/// </summary>
		/// <param name="collection">The bag that might be wrapped.</param>
		/// <returns>
		/// <see langword="true" /> if the <paramref name="collection"/> is equal to the
		/// wrapped collection by object reference.
		/// </returns>
		public override bool IsWrapper(object collection)
		{
			return bag == collection;
		}

		public override ICollection GetOrphans(object snapshot, string entityName)
		{
			IList sn = (IList) snapshot;
			ArrayList result = new ArrayList();
			result.AddRange(sn);
			// HACK: careful with cast here...
			IdentityRemoveAll(result, (ICollection) bag, entityName, Session);
			return result;
		}

		public override void DelayedAddAll(ICollection coll, ICollectionPersister persister)
		{
			bool isOneToMany = persister.IsOneToMany;
			foreach (T obj in coll)
			{
				if (isOneToMany && bag.Contains(obj))
				{
					// Skip this
					continue;
				}
				bag.Add(obj);
			}
		}

		#endregion

		#region IList Members

		// when the method/property takes an "object" parameter then 
		// make sure to use a reference to the non-generic interface
		// so we can ensure that the same exception gets thrown as if
		// there was no NHibernate wrapper around the collection.  For
		// the methods that don't take an "object" parameter then we
		// can just use "this" so we don't duplicate the Read/Write 
		// logic.

		int IList.Add(object value)
		{
			if (!QueueAdd(value))
			{
				Write();
				return ((IList) bag).Add(value);
			}
			else
			{
				return -1;
			}
		}

		void IList.Clear()
		{
			this.Clear();
		}

		bool IList.Contains(object value)
		{
			Read();
			return ((IList) bag).Contains(value);
		}

		int IList.IndexOf(object value)
		{
			Read();
			return ((IList) bag).IndexOf(value);
		}

		void IList.Insert(int index, object value)
		{
			Initialize(true);
			((IList) bag).Insert(index, value);
			Dirty();
		}

		bool IList.IsFixedSize
		{
			get { return false; }
		}

		bool IList.IsReadOnly
		{
			get { return false; }
		}

		void IList.Remove(object value)
		{
			Initialize(true);
			int oldCount = bag.Count;
			((IList) bag).Remove(value);
			if (oldCount != bag.Count)
			{
				Dirty();
			}
		}

		void IList.RemoveAt(int index)
		{
			this.RemoveAt(index);
		}

		object IList.this[int index]
		{
			get { return this[index]; }
			set
			{
				Write();
				((IList) bag)[index] = value;
			}
		}

		#endregion

		#region ICollection Members

		void ICollection.CopyTo(Array array, int index)
		{
			Read();
			((IList) bag).CopyTo(array, index);
		}

		int ICollection.Count
		{
			get { return this.Count; }
		}

		bool ICollection.IsSynchronized
		{
			get { return false; }
		}

		object ICollection.SyncRoot
		{
			get { return this; }
		}

		#endregion

		public override IEnumerable Entries(ICollectionPersister persister)
		{
			return bag;
		}

		public override bool RowUpdatePossible
		{
			get { return false; }
		}
	}
}

⌨️ 快捷键说明

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