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

📄 querytranslator.cs

📁 NHibernate NET开发者所需的
💻 CS
📖 第 1 页 / 共 4 页
字号:
		/// <summary> 
		/// WARNING: side-effecty
		/// </summary>
		private SqlString RenderScalarSelect()
		{
			bool isSubselect = superQuery != null;

			SqlStringBuilder buf = new SqlStringBuilder();

			if (scalarTypes.Count == 0)
			{
				//ie. no select clause
				int size = returnedTypes.Count;
				for (int k = 0; k < size; k++)
				{
					scalarTypes.Add(NHibernateUtil.Entity(persisters[k].EntityName));

					string[] _names = persisters[k].IdentifierColumnNames;
					for (int i = 0; i < _names.Length; i++)
					{
						buf.Add(returnedTypes[k].ToString()).Add(StringHelper.Dot.ToString()).Add(_names[i]);
						if (!isSubselect)
						{
							buf.Add(" as ").Add(ScalarName(k, i));
						}
						if (i != _names.Length - 1 || k != size - 1)
						{
							buf.Add(StringHelper.CommaSpace);
						}
					}
				}
			}
			else
			{
				//there _was_ a select clause
				int c = 0;
				bool nolast = false; //real hacky...
				int parenCount = 0; // used to count the nesting of parentheses
				for (int tokenIdx = 0; tokenIdx < scalarSelectTokens.Count; tokenIdx++)
				{
					SqlString next = scalarSelectTokens[tokenIdx];
					if (next.Count == 1)
					{
						string token = next.ToString();
						string lc = token.ToLowerInvariant();
						ISQLFunction func = Factory.SQLFunctionRegistry.FindSQLFunction(lc);
						if (func != null)
						{
							// Render the HQL function
							SqlString renderedFunction = RenderFunctionClause(func, scalarSelectTokens, ref tokenIdx);
							buf.Add(renderedFunction);
						}
						else
						{
							if (StringHelper.OpenParen.Equals(token))
							{
								parenCount++;
							}
							else if (StringHelper.ClosedParen.Equals(token))
							{
								parenCount--;
							}
							else if (lc.Equals(StringHelper.CommaSpace))
							{
								if (nolast)
								{
									nolast = false;
								}
								else
								{
									if (!isSubselect && parenCount == 0)
									{
										buf.Add(" as ").Add(ScalarName(c++, 0));
									}
								}
							}

							buf.Add(token);
							if (lc.Equals("distinct") || lc.Equals("all"))
							{
								buf.Add(" ");
							}
						}
					}
					else
					{
						nolast = true;
						int i = 0;
						foreach (object token in next.Parts)
						{
							buf.AddObject(token);
							if (!isSubselect)
							{
								buf.Add(" as ").Add(ScalarName(c, i));
							}
							if (i != next.Count - 1)
							{
								buf.Add(StringHelper.CommaSpace);
							}
							i++;
						}
						c++;
					}
				}
				if (!isSubselect && !nolast)
				{
					buf.Add(" as ").Add(ScalarName(c++, 0));
				}
			}

			return buf.ToSqlString();
		}

		private void RenderFunctions(IList<SqlString> tokens)
		{
			for (int tokenIdx = 0; tokenIdx < tokens.Count; tokenIdx++)
			{
				string token = tokens[tokenIdx].ToString().ToLowerInvariant();
				ISQLFunction func = Factory.SQLFunctionRegistry.FindSQLFunction(token);
				if (func != null)
				{
					int flTokenIdx = tokenIdx;
					SqlString renderedFunction = RenderFunctionClause(func, tokens, ref flTokenIdx);
					// At this point we have the trunk that represents the function with its 
					// arguments enclosed in parens. Now all token in the tokens list will be
					// removed from the original list and replaced with the rendered function.
					for (int i = 0; i < flTokenIdx - tokenIdx; i++)
					{
						tokens.RemoveAt(tokenIdx + 1);
					}
					tokens[tokenIdx] = new SqlString(renderedFunction);
				}
			}
		}

		/// <summary>
		/// Extract the complete clause of function.
		/// </summary>
		/// <param name="tokens">The list of tokens</param>
		/// <param name="tokenIdx">The index of the list that represent the founded function.</param>
		/// <returns>String trepresentation of each token.</returns>
		/// <remarks>Each token can be string or SqlString </remarks>
		private IList<SqlString> ExtractFunctionClause(IList<SqlString> tokens, ref int tokenIdx)
		{
			SqlString funcName = tokens[tokenIdx];
			IList<SqlString> functionTokens = new List<SqlString>();
			functionTokens.Add(funcName);
			tokenIdx++;
			if (tokenIdx >= tokens.Count ||
				!StringHelper.OpenParen.Equals(tokens[tokenIdx].ToString()))
			{
				// All function with arguments have the syntax
				// <function name> <left paren> <arguments> <right paren>
				throw new QueryException("'(' expected after function " + funcName);
			}
			functionTokens.Add(new SqlString(StringHelper.OpenParen));
			tokenIdx++;
			int parenCount = 1;
			for (; tokenIdx < tokens.Count && parenCount > 0; tokenIdx++)
			{
				if (tokens[tokenIdx].StartsWithCaseInsensitive(ParserHelper.HqlVariablePrefix) || tokens[tokenIdx].ToString().Equals(StringHelper.SqlParameter))
				{
					functionTokens.Add(SqlString.Parameter);
				}
				else
				{
					functionTokens.Add(tokens[tokenIdx]);
				}
				if (StringHelper.OpenParen.Equals(tokens[tokenIdx].ToString()))
				{
					parenCount++;
				}
				else if (StringHelper.ClosedParen.Equals(tokens[tokenIdx].ToString()))
				{
					parenCount--;
				}
			}
			tokenIdx--; // position of the last managed token
			if (parenCount > 0)
			{
				throw new QueryException("')' expected for function " + funcName);
			}
			return functionTokens;
		}

		private SqlString RenderFunctionClause(ISQLFunction func, IList<SqlString> tokens, ref int tokenIdx)
		{
			IList<SqlString> functionTokens;
			if (!func.HasArguments)
			{
				// The function doesn't work with arguments.
				if (func.HasParenthesesIfNoArguments)
					ExtractFunctionClause(tokens, ref tokenIdx);

				// The function render simply translate its name for a specific dialect.
				return func.Render(new ArrayList(), Factory);
			}
			functionTokens = ExtractFunctionClause(tokens, ref tokenIdx);

			IFunctionGrammar fg = func as IFunctionGrammar;
			if (fg == null)
				fg = new CommonGrammar();

			IList args = new ArrayList();
			SqlStringBuilder argBuf = new SqlStringBuilder();
			// Extract args spliting first 2 token because are: FuncName(
			// last token is ')'
			// To allow expressions like arg (ex:5+5) all tokens between 'argument separator' or
			// a 'know argument' are compacted in a string, 
			// because many HQL function expect IList<string> like args in Render method.
			// This solution give us the ability to use math expression in common function. 
			// Ex: sum(a.Prop+10), cast(yesterday-1 as date)
			for (int argIdx = 2; argIdx < functionTokens.Count - 1; argIdx++)
			{
				object token = functionTokens[argIdx];
				if (fg.IsKnownArgument(token.ToString()))
				{
					if (argBuf.Count > 0)
					{
						// end of the previous argument
						args.Add(argBuf.ToSqlString());
						argBuf = new SqlStringBuilder();
					}
					args.Add(token);
				}
				else if (fg.IsSeparator(token.ToString()))
				{
					// argument end
					if (argBuf.Count > 0)
					{
						args.Add(argBuf.ToSqlString());
						argBuf = new SqlStringBuilder();
					}
				}
				else
				{
					ISQLFunction nfunc = Factory.SQLFunctionRegistry.FindSQLFunction(token.ToString().ToLowerInvariant());
					if (nfunc != null)
					{
						// the token is a nested function call
						argBuf.Add(RenderFunctionClause(nfunc, functionTokens, ref argIdx));
					}
					else
					{
						// the token is a part of an argument (every thing else)
						argBuf.AddObject(token);
					}
				}
			}
			// Add the last arg
			if (argBuf.Count > 0)
				args.Add(argBuf.ToSqlString());
			return func.Render(args, Factory);
		}

		private class Selector : JoinSequence.ISelector
		{
			private QueryTranslator outer;

			public Selector(QueryTranslator outer)
			{
				this.outer = outer;
			}

			public bool IncludeSubclasses(string alias)
			{
				bool include = outer.returnedTypes.Contains(alias) && !outer.IsShallowQuery;
				return include;
			}
		}

		private void MergeJoins(JoinFragment ojf)
		{
			foreach (KeyValuePair<string, JoinSequence> de in joins)
			{
				string name = de.Key;
				JoinSequence join = de.Value;
				join.SetSelector(new Selector(this));

				if (typeMap.ContainsKey(name))
				{
					ojf.AddFragment(join.ToJoinFragment(enabledFilters, true));
				}
				else if (collections.ContainsKey(name))
				{
					ojf.AddFragment(join.ToJoinFragment(enabledFilters, true));
				}
				else
				{
					//name from a super query (a bit inelegant that it shows up here)
				}
			}
		}

		public ISet<string> QuerySpaces
		{
			get { return querySpaces; }
		}

		/// <summary>
		/// Is this query called by Scroll() or Iterate()?
		/// </summary>
		/// <value>true if it is, false if it is called by find() or list()</value>
		public bool IsShallowQuery
		{
			get { return shallowQuery; }
		}

		internal bool Distinct
		{
			set { distinct = value; }
		}

		/// <summary></summary>
		public bool IsSubquery
		{
			get { return superQuery != null; }
		}

		protected override ICollectionPersister[] CollectionPersisters
		{
			get { return fetchedCollections.CollectionPersisters; }
		}

		protected override string[] CollectionSuffixes
		{
			get { return fetchedCollections.CollectionSuffixes; }
			set { throw new InvalidOperationException("QueryTranslator.CollectionSuffixes_set"); }
		}

		public void AddCollectionToFetch(string role, string name, string ownerName, string entityName)
		{
			IQueryableCollection persister = GetCollectionPersister(role);
			fetchedCollections.Add(name, persister, ownerName);
			if (persister.ElementType.IsEntityType)
			{
				AddEntityToFetch(entityName);
			}
		}

		protected override string[] Suffixes
		{
			get { return suffixes; }
			set { suffixes = value; }
		}

		/// <remarks>Used for collection filters</remarks>
		protected void AddFromAssociation(string elementName, string collectionRole)
		{
			//q.addCollection(collectionName, collectionRole);
			IType collectionElementType = GetCollectionPersister(collectionRole).ElementType;
			if (!collectionElementType.IsEntityType)
			{
				throw new QueryException("collection of values in filter: " + elementName);
			}

			IQueryableCollection persister = GetCollectionPersister(collectionRole);
			string[] keyColumnNames = persister.KeyColumnNames;
			//if (keyColumnNames.Length!=1) throw new QueryException("composite-key collecion in filter: " + collectionRole);

			string collectionName;
			JoinSequence join = new JoinSequence(Factory);
			collectionName = persister.IsOneToMany ? elementName : CreateNameForCollection(collectionRole);
			join.SetRoot(persister, collectionName);
			if (!persister.IsOneToMany)
			{
				//many-to-many
				AddCollection(collectionName, collectionRole);

				try
				{
					join.AddJoin(
						(IAssociationType) persister.ElementType,
						elementName,
						JoinType.InnerJoin,
						persister.GetElementColumnNames(collectionName));
				}
				catch (MappingException me)
				{
					throw new QueryException(me);
				}
			}
			join.AddCondition(collectionName, keyColumnNames, " = ", true);
			EntityType elmType = (EntityType) collectionElementType;
			AddFrom(elementName, elmType.GetAssociatedEntityName(), join);
		}

		internal string GetPathAlias(string path)
		{
			string result;
			pathAliases.TryGetValue(path, out result);
			return result;
		}

		internal JoinSequence GetPathJoin(string path)
		{
			JoinSequence result;
			pathJoins.TryGetValue(path, out result);
			return result;
		}

		internal void AddPathAliasAndJoin(string path, string alias, JoinSequence joinSequence)
		{
			pathAliases.Add(path, alias);
			pathJoins.Add(path, joinSequence);
		}

		public IList List(ISessionImplementor session, QueryParameters queryParameters)
		{
			return List(session, queryParameters, QuerySpaces, actualReturnTypes);
		}

		public IEnumerable GetEnumerable(QueryParameters parameters, ISessionImplementor session)
		{
			bool stats = session.Factory.Statistics.IsStatisticsEnabled;
			long startTime = 0;
			if (stats)
				startTime = DateTime.Now.Ticks;

			IDbCommand cmd = PrepareQueryCommand(parameters, false, session);

			// This IDataReader is disposed of in EnumerableImpl.Dispose
			IDataReader rs = GetResultSet(cmd, parameters.HasAutoDiscoverScalarTypes, false, parameters.RowSelection, session);
			HolderInstantiator hi =
				HolderInstantiator.CreateClassicHolderInstantiator(holderConstructor, parameters.ResultTransformer);
			IEnumerable result =
				new EnumerableImpl(rs, cmd, session, ReturnTypes, ScalarColumnNames, parameters.RowSelection, hi);
			if (stats)
			{
				session.Factory.StatisticsImplementor.QueryExecuted("HQL: " + queryString, 0, (DateTime.Now.Ticks  - startTime));
				// NH: Different behavior (H3.2 use QueryLoader in AST parser) we need statistic for orginal query too.
				// probably we have a bug some where else for statistic RowCount
				session.Factory.StatisticsImplementor.QueryExecuted(QueryIdentifier, 0, (DateTime.Now.Ticks - startTime));
			}
			return result;
		}

		public static string[] ConcreteQueries(string query, ISessionFactoryImplementor factory)

⌨️ 快捷键说明

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