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

📄 unionsubclassentitypersister.cs

📁 NHibernate NET开发者所需的
💻 CS
字号:
using System.Collections.Generic;
using System.Text;
using Iesi.Collections.Generic;
using NHibernate.Cache;
using NHibernate.Cfg;
using NHibernate.Engine;
using NHibernate.Id;
using NHibernate.Mapping;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Util;

namespace NHibernate.Persister.Entity
{
	public class UnionSubclassEntityPersister : AbstractEntityPersister
	{
		private readonly string subquery;
		private readonly string tableName;
		private readonly string[] subclassClosure;
		private readonly string[] spaces;
		private readonly string[] subclassSpaces;
		private readonly string discriminatorSQLValue;
		private readonly object discriminatorValue;
		private readonly Dictionary<int, string> subclassByDiscriminatorValue = new Dictionary<int, string>();
		private readonly string[] constraintOrderedTableNames;
		private readonly string[][] constraintOrderedKeyColumnNames;

		public UnionSubclassEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, 
			ISessionFactoryImplementor factory, IMapping mapping):base(persistentClass, cache, factory)
		{
			if (IdentifierGenerator is IdentityGenerator)
			{
				throw new MappingException("Cannot use identity column key generation with <union-subclass> mapping for: " + EntityName);
			}

			// TABLE

			tableName =
				persistentClass.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName,
				                                       factory.Settings.DefaultSchemaName);

			#region Custom SQL

			SqlString sql;
			bool callable;
			ExecuteUpdateResultCheckStyle checkStyle;

			sql = persistentClass.CustomSQLInsert;
			callable = sql != null && persistentClass.IsCustomInsertCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLInsertCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLInsert = new SqlString[] { sql };
			insertCallable = new bool[] { callable };
			insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			sql = persistentClass.CustomSQLUpdate;
			callable = sql != null && persistentClass.IsCustomUpdateCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLUpdateCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLUpdate = new SqlString[] { sql };
			updateCallable = new bool[] { callable };
			updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			sql = persistentClass.CustomSQLDelete;
			callable = sql != null && persistentClass.IsCustomDeleteCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLDeleteCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLDelete = new SqlString[] { sql };
			deleteCallable = new bool[] { callable };
			deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			#endregion

			discriminatorValue = persistentClass.SubclassId;
			discriminatorSQLValue = persistentClass.SubclassId.ToString();

			#region PROPERTIES

			int subclassSpan = persistentClass.SubclassSpan + 1;
			subclassClosure = new string[subclassSpan];
			subclassClosure[0] = EntityName;

			#endregion

			#region SUBCLASSES

			subclassByDiscriminatorValue[persistentClass.SubclassId] = persistentClass.EntityName;
			if (persistentClass.IsPolymorphic)
			{
				int k = 1;
				foreach (Subclass sc in persistentClass.SubclassIterator)
				{
					subclassClosure[k++] = sc.EntityName;
					subclassByDiscriminatorValue[sc.SubclassId] = sc.EntityName;
				}
			}

			#endregion

			#region SPACES
			//TODO: i'm not sure, but perhaps we should exclude abstract denormalized tables?

			int spacesSize = 1 + persistentClass.SynchronizedTables.Count;
			spaces = new string[spacesSize];
			spaces[0] = tableName;
			IEnumerator<string> iSyncTab = persistentClass.SynchronizedTables.GetEnumerator();
			for (int i = 1; i < spacesSize; i++)
			{
				iSyncTab.MoveNext();
				spaces[i] = iSyncTab.Current;
			}

			HashedSet<string> subclassTables = new HashedSet<string>();
			foreach (Table table in persistentClass.SubclassTableClosureIterator)
			{
				subclassTables.Add(
					table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName));
			}
			subclassSpaces = new string[subclassTables.Count];
			subclassTables.CopyTo(subclassSpaces, 0);

			subquery = GenerateSubquery(persistentClass, mapping);

			if (IsMultiTable)
			{
				int idColumnSpan = IdentifierColumnSpan;
				List<string> tableNames = new List<string>();
				List<string[]> keyColumns = new List<string[]>();
				if (!IsAbstract)
				{
					tableNames.Add(tableName);
					keyColumns.Add(IdentifierColumnNames);
				}
				foreach (Table tab in persistentClass.SubclassTableClosureIterator)
				{
					if (!tab.IsAbstractUnionTable)
					{
						string _tableName =
							tab.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
						tableNames.Add(_tableName);

						List<string> key = new List<string>(idColumnSpan);
						foreach (Column column in tab.PrimaryKey.ColumnIterator)
							key.Add(column.GetQuotedName(factory.Dialect));

						keyColumns.Add(key.ToArray());
					}					
				}

				constraintOrderedTableNames = tableNames.ToArray();
				constraintOrderedKeyColumnNames = keyColumns.ToArray();
			}
			else
			{
				constraintOrderedTableNames = new string[] { tableName };
				constraintOrderedKeyColumnNames = new string[][] { IdentifierColumnNames };
			}
			#endregion

			InitLockers();

			InitSubclassPropertyAliasesMap(persistentClass);

			PostConstruct(mapping);
		}

		public override string[] QuerySpaces
		{
			get { return subclassSpaces; }
		}

		public override Type.IType DiscriminatorType
		{
			get { return NHibernateUtil.Int32; }
		}

		public override string DiscriminatorSQLValue
		{
			get { return discriminatorSQLValue;}
		}

		public override object DiscriminatorValue
		{
			get { return discriminatorValue; }
		}

		public string[] SubclassClosure
		{
			get { return subclassClosure; }
		}

		public override string[] PropertySpaces
		{
			get { return spaces; }
		}

		protected internal override int[] PropertyTableNumbersInSelect
		{
			get { return new int[PropertySpan]; }
		}

		public override bool IsMultiTable
		{
			get
			{
				// This could also just be true all the time...
				return IsAbstract || HasSubclasses;
			}
		}

		protected override int[] SubclassColumnTableNumberClosure
		{
			get { return new int[SubclassColumnClosure.Length]; }
		}

		protected override int[] SubclassFormulaTableNumberClosure
		{
			get { return new int[SubclassFormulaClosure.Length]; }
		}

		protected internal override int[] PropertyTableNumbers
		{
			get { return new int[PropertySpan]; }
		}

		public override string[] ConstraintOrderedTableNameClosure
		{
			get { return constraintOrderedTableNames; }
		}

		public override string[][] ContraintOrderedTableKeyColumnClosure
		{
			get { return constraintOrderedKeyColumnNames; }
		}

		public override string TableName
		{
			get { return subquery; }
		}

		public override string GetSubclassForDiscriminatorValue(object value)
		{
			string result;
			subclassByDiscriminatorValue.TryGetValue((int)value, out result);
			return result;
		}

		protected internal virtual bool IsDiscriminatorFormula
		{
			get { return false; }
		}

		/// <summary> Generate the SQL that selects a row by id</summary>
		protected internal virtual SqlString GenerateSelectString(LockMode lockMode)
		{
			SqlSimpleSelectBuilder select = new SqlSimpleSelectBuilder(Factory.Dialect, Factory)
				.SetLockMode(lockMode)
				.SetTableName(TableName)
				.AddColumns(IdentifierColumnNames)
				.AddColumns(SubclassColumnClosure, SubclassColumnAliasClosure, SubclassColumnLazyiness)
				.AddColumns(SubclassFormulaClosure, SubclassFormulaAliasClosure, SubclassFormulaLazyiness);
			//TODO: include the rowids!!!!
			if (HasSubclasses)
			{
				if (IsDiscriminatorFormula)
				{
					select.AddColumn(DiscriminatorFormula, DiscriminatorAlias);
				}
				else
				{
					select.AddColumn(DiscriminatorColumnName, DiscriminatorAlias);
				}
			}
			if (Factory.Settings.IsCommentsEnabled)
			{
				select.SetComment("load " + EntityName);
			}
			return select.AddWhereFragment(IdentifierColumnNames, IdentifierType, "=").ToSqlString();
		}

		protected internal string DiscriminatorFormula
		{
			get { return null; } // NH : what this mean ? (see GenerateSelectString) 
		}

		protected override string GetTableName(int table)
		{
			return tableName;
		}

		protected override string[] GetKeyColumns(int table)
		{
			return IdentifierColumnNames;
		}

		protected override bool IsTableCascadeDeleteEnabled(int j)
		{
			return false;
		}

		protected override bool IsPropertyOfTable(int property, int j)
		{
			return true;
		}

		public override string FromTableFragment(string name)
		{
			return TableName + ' ' + name;
		}

		public override string FilterFragment(string alias)
		{
			return HasWhere ? " and " + GetSQLWhereString(alias) : string.Empty;
		}

		public override string GetSubclassPropertyTableName(int i)
		{
			return TableName; //ie. the subquery! yuck!
		}

		protected override void AddDiscriminatorToSelect(SelectFragment select, string name, string suffix)
		{
			select.AddColumn(name, DiscriminatorColumnName, DiscriminatorAlias);
		}

		protected override int GetSubclassPropertyTableNumber(int i)
		{
			return 0;
		}

		public override int GetSubclassPropertyTableNumber(string propertyName)
		{
			return 0;
		}

		protected override int TableSpan
		{
			get { return 1; }
		}

		protected string GenerateSubquery(PersistentClass model, IMapping mapping)
		{
			Dialect.Dialect dialect = Factory.Dialect;
			Settings settings = Factory.Settings;

			if (!model.HasSubclasses)
			{
				return model.Table.GetQualifiedName(dialect, settings.DefaultCatalogName, settings.DefaultSchemaName);
			}

			HashedSet<Column> columns = new HashedSet<Column>();
			foreach (Table table in model.SubclassTableClosureIterator)
			{
				if (!table.IsAbstractUnionTable)
				{
					foreach (Column column in table.ColumnIterator)
						columns.Add(column);
				}
			}

			StringBuilder buf = new StringBuilder().Append("( ");
			IEnumerable<PersistentClass> siter =
				new JoinedEnumerable<PersistentClass>(new SingletonEnumerable<PersistentClass>(model),
				                                      new SafetyEnumerable<PersistentClass>(model.SubclassIterator));

			foreach (PersistentClass clazz in siter)
			{
				Table table = clazz.Table;
				if (!table.IsAbstractUnionTable)
				{
					buf.Append("select ");
					foreach (Column col in columns)
					{
						if (!table.ContainsColumn(col))
						{
							SqlType sqlType = col.GetSqlTypeCode(mapping);
							buf.Append(dialect.GetSelectClauseNullString(sqlType)).Append(" as ");
						}
						buf.Append(col.Name);
						buf.Append(StringHelper.CommaSpace);
					}
					buf.Append(clazz.SubclassId).Append(" as clazz_");
					buf.Append(" from ").Append(table.GetQualifiedName(dialect, Factory.DefaultSchema));
					buf.Append(" union ");
					if (dialect.SupportsUnionAll)
						buf.Append("all ");
				}
			}

			if (buf.Length > 2)
			{
				//chop the last union (all)
				buf.Length -= (dialect.SupportsUnionAll ? 11 : 7); //" union " : "all "
			}

			return buf.Append(" )").ToString();
		}

		protected override string[] GetSubclassTableKeyColumns(int j)
		{
			if (j != 0)
				throw new AssertionFailure("only one table");
			return IdentifierColumnNames;
		}

		public override string GetSubclassTableName(int j)
		{
			if (j != 0)
				throw new AssertionFailure("only one table");
			return tableName;
		}

		protected override int SubclassTableSpan
		{
			get { return 1; }
		}

		protected override bool IsClassOrSuperclassTable(int j)
		{
			if (j != 0)
				throw new AssertionFailure("only one table");
			return true;
		}

		public override string GetPropertyTableName(string propertyName)
		{
			//TODO: check this....
			return TableName;
		}
	}
}

⌨️ 快捷键说明

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