PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NHibernate/Impl/ExpressionQueryImpl.cs

https://github.com/okb/nhibernate-core
C# | 281 lines | 222 code | 53 blank | 6 comment | 10 complexity | d60e0a4151d076674dfe6d03986edd42 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, LGPL-3.0, Apache-2.0, CC-BY-SA-3.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using NHibernate.Engine;
  7. using NHibernate.Engine.Query;
  8. using NHibernate.Hql.Ast.ANTLR;
  9. using NHibernate.Hql.Ast.ANTLR.Tree;
  10. using NHibernate.Hql.Ast.ANTLR.Util;
  11. using NHibernate.Type;
  12. using NHibernate.Util;
  13. namespace NHibernate.Impl
  14. {
  15. internal class ExpressionQueryImpl : AbstractQueryImpl
  16. {
  17. private readonly Dictionary<string, LockMode> _lockModes = new Dictionary<string, LockMode>(2);
  18. public ExpressionQueryImpl(IQueryExpression queryExpression, ISessionImplementor session, ParameterMetadata parameterMetadata)
  19. : base(queryExpression.Key, FlushMode.Unspecified, session, parameterMetadata)
  20. {
  21. QueryExpression = queryExpression;
  22. }
  23. public IQueryExpression QueryExpression { get; private set; }
  24. protected internal override IDictionary<string, LockMode> LockModes
  25. {
  26. get { return _lockModes; }
  27. }
  28. public override IQuery SetLockMode(string alias, LockMode lockMode)
  29. {
  30. _lockModes[alias] = lockMode;
  31. return this;
  32. }
  33. public override int ExecuteUpdate()
  34. {
  35. throw new NotImplementedException();
  36. }
  37. public override IEnumerable Enumerable()
  38. {
  39. throw new NotImplementedException();
  40. }
  41. public override IEnumerable<T> Enumerable<T>()
  42. {
  43. throw new NotImplementedException();
  44. }
  45. public override IList List()
  46. {
  47. VerifyParameters();
  48. IDictionary<string, TypedValue> namedParams = NamedParams;
  49. Before();
  50. try
  51. {
  52. return Session.List(ExpandParameters(namedParams), GetQueryParameters(namedParams));
  53. }
  54. finally
  55. {
  56. After();
  57. }
  58. }
  59. /// <summary>
  60. /// Warning: adds new parameters to the argument by side-effect, as well as mutating the query expression tree!
  61. /// </summary>
  62. protected internal IQueryExpression ExpandParameters(IDictionary<string, TypedValue> namedParamsCopy)
  63. { // TODO: On master, we can make this method protected non-internal again.
  64. if (namedParameterLists.Count == 0)
  65. {
  66. // Short circuit straight out
  67. return QueryExpression;
  68. }
  69. // Build a map from single parameters to lists
  70. var map = new Dictionary<string, List<string>>();
  71. foreach (var me in namedParameterLists)
  72. {
  73. string name = me.Key;
  74. var vals = (ICollection) me.Value.Value;
  75. IType type = me.Value.Type;
  76. if (vals.Count == 1)
  77. {
  78. // No expansion needed here
  79. IEnumerator iter = vals.GetEnumerator();
  80. iter.MoveNext();
  81. namedParamsCopy[name] = new TypedValue(type, iter.Current, Session.EntityMode);
  82. continue;
  83. }
  84. var aliases = new List<string>();
  85. int i = 0;
  86. bool isJpaPositionalParam = parameterMetadata.GetNamedParameterDescriptor(name).JpaStyle;
  87. foreach (object obj in vals)
  88. {
  89. string alias = (isJpaPositionalParam ? 'x' + name : name + StringHelper.Underscore) + i++ + StringHelper.Underscore;
  90. namedParamsCopy[alias] = new TypedValue(type, obj, Session.EntityMode);
  91. aliases.Add(alias);
  92. }
  93. map.Add(name, aliases);
  94. }
  95. IASTNode newTree = ParameterExpander.Expand(QueryExpression.Translate(Session.Factory), map);
  96. var key = new StringBuilder(QueryExpression.Key);
  97. map.Aggregate(key, (sb, kvp) =>
  98. {
  99. sb.Append(' ');
  100. sb.Append(kvp.Key);
  101. sb.Append(':');
  102. kvp.Value.Aggregate(sb, (sb2, str) => sb2.Append(str));
  103. return sb;
  104. });
  105. return new ExpandedQueryExpression(QueryExpression, newTree, key.ToString());
  106. }
  107. public override void List(IList results)
  108. {
  109. throw new NotImplementedException();
  110. }
  111. public override IList<T> List<T>()
  112. {
  113. throw new NotImplementedException();
  114. }
  115. }
  116. internal class ExpandedQueryExpression : IQueryExpression
  117. {
  118. private readonly IASTNode _tree;
  119. public ExpandedQueryExpression(IQueryExpression queryExpression, IASTNode tree, string key)
  120. {
  121. _tree = tree;
  122. Key = key;
  123. Type = queryExpression.Type;
  124. ParameterDescriptors = queryExpression.ParameterDescriptors;
  125. }
  126. #region IQueryExpression Members
  127. public IASTNode Translate(ISessionFactoryImplementor sessionFactory)
  128. {
  129. return _tree;
  130. }
  131. public string Key { get; private set; }
  132. public System.Type Type { get; private set; }
  133. public IList<NamedParameterDescriptor> ParameterDescriptors { get; private set; }
  134. #endregion
  135. }
  136. internal class ParameterExpander
  137. {
  138. private readonly Dictionary<string, List<string>> _map;
  139. private readonly IASTNode _tree;
  140. private ParameterExpander(IASTNode tree, Dictionary<string, List<string>> map)
  141. {
  142. _tree = tree;
  143. _map = map;
  144. }
  145. public static IASTNode Expand(IASTNode tree, Dictionary<string, List<string>> map)
  146. {
  147. var expander = new ParameterExpander(tree, map);
  148. return expander.Expand();
  149. }
  150. private IASTNode Expand()
  151. {
  152. IList<IASTNode> parameters = ParameterDetector.LocateParameters(_tree, new HashSet<string>(_map.Keys));
  153. var nodeMapping = new Dictionary<IASTNode, IEnumerable<IASTNode>>();
  154. foreach (IASTNode param in parameters)
  155. {
  156. IASTNode paramName = param.GetChild(0);
  157. List<string> aliases = _map[paramName.Text];
  158. var astAliases = new List<IASTNode>();
  159. foreach (string alias in aliases)
  160. {
  161. IASTNode astAlias = param.DupNode();
  162. IASTNode astAliasName = paramName.DupNode();
  163. astAliasName.Text = alias;
  164. astAlias.AddChild(astAliasName);
  165. astAliases.Add(astAlias);
  166. }
  167. nodeMapping.Add(param, astAliases);
  168. }
  169. return DuplicateTree(_tree, nodeMapping);
  170. }
  171. private static IASTNode DuplicateTree(IASTNode ast, IDictionary<IASTNode, IEnumerable<IASTNode>> nodeMapping)
  172. {
  173. IASTNode thisNode = ast.DupNode();
  174. foreach (IASTNode child in ast)
  175. {
  176. IEnumerable<IASTNode> candidate;
  177. if (nodeMapping.TryGetValue(child, out candidate))
  178. {
  179. foreach (IASTNode replacement in candidate)
  180. {
  181. thisNode.AddChild(replacement);
  182. }
  183. }
  184. else
  185. {
  186. thisNode.AddChild(DuplicateTree(child, nodeMapping));
  187. }
  188. }
  189. return thisNode;
  190. }
  191. }
  192. internal class ParameterDetector : IVisitationStrategy
  193. {
  194. private readonly List<IASTNode> _nodes;
  195. private readonly HashSet<string> _parameterNames;
  196. private readonly IASTNode _tree;
  197. private ParameterDetector(IASTNode tree, HashSet<string> parameterNames)
  198. {
  199. _tree = tree;
  200. _parameterNames = parameterNames;
  201. _nodes = new List<IASTNode>();
  202. }
  203. #region IVisitationStrategy Members
  204. public void Visit(IASTNode node)
  205. {
  206. if ((node.Type == HqlSqlWalker.PARAM) || (node.Type == HqlSqlWalker.COLON))
  207. {
  208. string name = node.GetChild(0).Text;
  209. if (_parameterNames.Contains(name))
  210. {
  211. _nodes.Add(node);
  212. }
  213. }
  214. }
  215. #endregion
  216. public static IList<IASTNode> LocateParameters(IASTNode tree, HashSet<string> parameterNames)
  217. {
  218. var detector = new ParameterDetector(tree, parameterNames);
  219. return detector.LocateParameters();
  220. }
  221. private IList<IASTNode> LocateParameters()
  222. {
  223. var nodeTraverser = new NodeTraverser(this);
  224. nodeTraverser.TraverseDepthFirst(_tree);
  225. return _nodes;
  226. }
  227. }
  228. }