PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/referencesource/System.Data.DataSetExtensions/System/Data/EnumerableRowCollection.cs

https://github.com/pruiz/mono
C# | 356 lines | 254 code | 40 blank | 62 comment | 32 complexity | 6061d1929197e76eb621bf274165abef MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //------------------------------------------------------------------------------
  2. // <copyright file="GenericEnumRowCollection.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. // <owner current="true" primary="false">Microsoft</owner>
  7. //------------------------------------------------------------------------------
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Collections;
  11. using System.Text;
  12. using System.Data;
  13. using System.Linq;
  14. using System.Diagnostics;
  15. using System.Linq.Expressions;
  16. using System.Collections.ObjectModel;
  17. using System.Data.DataSetExtensions;
  18. namespace System.Data
  19. {
  20. /// <summary>
  21. /// Provides an entry point so that Cast operator call can be intercepted within an extension method.
  22. /// </summary>
  23. public abstract class EnumerableRowCollection : IEnumerable
  24. {
  25. internal abstract Type ElementType { get; }
  26. internal abstract DataTable Table { get; }
  27. internal EnumerableRowCollection()
  28. {
  29. }
  30. IEnumerator IEnumerable.GetEnumerator()
  31. {
  32. return null;
  33. }
  34. }
  35. /// <summary>
  36. /// This class provides a wrapper for DataTables to allow for querying via LINQ.
  37. /// </summary>
  38. public class EnumerableRowCollection<TRow> : EnumerableRowCollection, IEnumerable<TRow>
  39. {
  40. private readonly DataTable _table;
  41. private readonly IEnumerable<TRow> _enumerableRows;
  42. private readonly List<Func<TRow, bool>> _listOfPredicates;
  43. // Stores list of sort expression in the order provided by user. E.g. order by, thenby, thenby descending..
  44. private readonly SortExpressionBuilder<TRow> _sortExpression;
  45. private readonly Func<TRow, TRow> _selector;
  46. #region Properties
  47. internal override Type ElementType
  48. {
  49. get
  50. {
  51. return typeof(TRow);
  52. }
  53. }
  54. internal IEnumerable<TRow> EnumerableRows
  55. {
  56. get
  57. {
  58. return _enumerableRows;
  59. }
  60. }
  61. internal override DataTable Table
  62. {
  63. get
  64. {
  65. return _table;
  66. }
  67. }
  68. #endregion Properties
  69. #region Constructors
  70. /// <summary>
  71. /// This constructor is used when Select operator is called with output Type other than input row Type.
  72. /// Basically fail on GetLDV(), but other LINQ operators must work.
  73. /// </summary>
  74. internal EnumerableRowCollection(IEnumerable<TRow> enumerableRows, bool isDataViewable, DataTable table)
  75. {
  76. Debug.Assert(!isDataViewable || table != null, "isDataViewable bug table is null");
  77. _enumerableRows = enumerableRows;
  78. if (isDataViewable)
  79. {
  80. _table = table;
  81. }
  82. _listOfPredicates = new List<Func<TRow, bool>>();
  83. _sortExpression = new SortExpressionBuilder<TRow>();
  84. }
  85. /// <summary>
  86. /// Basic Constructor
  87. /// </summary>
  88. internal EnumerableRowCollection(DataTable table)
  89. {
  90. _table = table;
  91. _enumerableRows = table.Rows.Cast<TRow>();
  92. _listOfPredicates = new List<Func<TRow, bool>>();
  93. _sortExpression = new SortExpressionBuilder<TRow>();
  94. }
  95. /// <summary>
  96. /// Copy Constructor that sets the input IEnumerable as enumerableRows
  97. /// Used to maintain IEnumerable that has linq operators executed in the same order as the user
  98. /// </summary>
  99. internal EnumerableRowCollection(EnumerableRowCollection<TRow> source, IEnumerable<TRow> enumerableRows, Func<TRow, TRow> selector)
  100. {
  101. Debug.Assert(null != enumerableRows, "null enumerableRows");
  102. _enumerableRows = enumerableRows;
  103. _selector = selector;
  104. if (null != source)
  105. {
  106. if (null == source._selector)
  107. {
  108. _table = source._table;
  109. }
  110. _listOfPredicates = new List<Func<TRow, bool>>(source._listOfPredicates);
  111. _sortExpression = source._sortExpression.Clone(); //deep copy the List
  112. }
  113. else
  114. {
  115. _listOfPredicates = new List<Func<TRow, bool>>();
  116. _sortExpression = new SortExpressionBuilder<TRow>();
  117. }
  118. }
  119. #endregion Constructors
  120. #region PublicInterface
  121. IEnumerator IEnumerable.GetEnumerator()
  122. {
  123. return GetEnumerator();
  124. }
  125. /// <summary>
  126. /// This method returns an strongly typed iterator
  127. /// for the underlying DataRow collection.
  128. /// </summary>
  129. /// <returns>
  130. /// A strongly typed iterator.
  131. /// </returns>
  132. public IEnumerator<TRow> GetEnumerator()
  133. {
  134. return _enumerableRows.GetEnumerator();
  135. }
  136. #endregion PublicInterface
  137. /// <summary>
  138. /// Evaluates filter and sort if necessary and returns
  139. /// a LinqDataView representing the LINQ query this class has collected.
  140. /// </summary>
  141. /// <returns>LinqDataView repesenting the LINQ query</returns>
  142. internal LinqDataView GetLinqDataView() //Called by AsLinqDataView
  143. {
  144. if ((null == _table) || !typeof(DataRow).IsAssignableFrom(typeof(TRow)))
  145. {
  146. throw DataSetUtil.NotSupported(Strings.ToLDVUnsupported);
  147. }
  148. LinqDataView view = null;
  149. #region BuildSinglePredicate
  150. Func<DataRow, bool> finalPredicate = null; //Conjunction of all .Where(..) predicates
  151. if ((null != _selector) && (0 < _listOfPredicates.Count))
  152. {
  153. // Hook up all individual predicates into one predicate
  154. // This delegate is a conjunction of multiple predicates set by the user
  155. // Note: This is a Short-Circuit Conjunction
  156. finalPredicate =
  157. delegate(DataRow row)
  158. {
  159. if (!Object.ReferenceEquals(row, _selector((TRow)(object)row)))
  160. {
  161. throw DataSetUtil.NotSupported(Strings.ToLDVUnsupported);
  162. }
  163. foreach (Func<TRow, bool> pred in _listOfPredicates)
  164. {
  165. if (!pred((TRow)(object)row))
  166. {
  167. return false;
  168. }
  169. }
  170. return true;
  171. };
  172. }
  173. else if (null != _selector)
  174. {
  175. finalPredicate =
  176. delegate(DataRow row)
  177. {
  178. if (!Object.ReferenceEquals(row, _selector((TRow)(object)row)))
  179. {
  180. throw DataSetUtil.NotSupported(Strings.ToLDVUnsupported);
  181. }
  182. return true;
  183. };
  184. }
  185. else if (0 < _listOfPredicates.Count)
  186. {
  187. finalPredicate =
  188. delegate(DataRow row)
  189. {
  190. foreach (Func<TRow, bool> pred in _listOfPredicates)
  191. {
  192. if (!pred((TRow)(object)row))
  193. {
  194. return false;
  195. }
  196. }
  197. return true;
  198. };
  199. }
  200. #endregion BuildSinglePredicate
  201. #region Evaluate Filter/Sort
  202. // All of this mess below is because we want to create index only once.
  203. //
  204. // If we only have filter, we set _view.Predicate - 1 index creation
  205. // If we only have sort, we set _view.SortExpression() - 1 index creation
  206. // If we have BOTH, we set them through the constructor - 1 index creation
  207. //
  208. // Filter AND Sort
  209. if ((null != finalPredicate) && (0 < _sortExpression.Count))
  210. {
  211. // A lot more work here because constructor does not know type K,
  212. // so the responsibility to create appropriate delegate comparers
  213. // is outside of the constructor.
  214. view = new LinqDataView(
  215. _table,
  216. finalPredicate, //Func() Predicate
  217. delegate(DataRow row) //System.Predicate
  218. {
  219. return finalPredicate(row);
  220. },
  221. delegate(DataRow a, DataRow b) //Comparison for DV for Index creation
  222. {
  223. return _sortExpression.Compare(
  224. _sortExpression.Select((TRow)(object)a),
  225. _sortExpression.Select((TRow)(object)b)
  226. );
  227. },
  228. delegate(object key, DataRow row) //Comparison_K_T for DV's Find()
  229. {
  230. return _sortExpression.Compare(
  231. (List<object>)key,
  232. _sortExpression.Select((TRow)(object)row)
  233. );
  234. },
  235. _sortExpression.CloneCast<DataRow>());
  236. }
  237. else if (null != finalPredicate)
  238. {
  239. //Only Filtering
  240. view = new LinqDataView(
  241. _table,
  242. finalPredicate,
  243. delegate(DataRow row) //System.Predicate
  244. {
  245. return finalPredicate(row);
  246. },
  247. null,
  248. null,
  249. _sortExpression.CloneCast<DataRow>());
  250. }
  251. else if (0 < _sortExpression.Count)
  252. {
  253. //Only Sorting
  254. view = new LinqDataView(
  255. _table,
  256. null,
  257. null,
  258. delegate(DataRow a, DataRow b)
  259. {
  260. return _sortExpression.Compare(_sortExpression.Select((TRow)(object)a), _sortExpression.Select((TRow)(object)b));
  261. },
  262. delegate(object key, DataRow row)
  263. {
  264. return _sortExpression.Compare((List<object>)key, _sortExpression.Select((TRow)(object)row));
  265. },
  266. _sortExpression.CloneCast<DataRow>());
  267. }
  268. else
  269. {
  270. view = new LinqDataView(_table, _sortExpression.CloneCast<DataRow>());
  271. }
  272. #endregion Evaluate Filter and Sort
  273. return view;
  274. }
  275. #region Add Single Filter/Sort Expression
  276. /// <summary>
  277. /// Used to add a filter predicate.
  278. /// A conjunction of all predicates are evaluated in LinqDataView
  279. /// </summary>
  280. internal void AddPredicate(Func<TRow, bool> pred)
  281. {
  282. Debug.Assert(pred != null);
  283. _listOfPredicates.Add(pred);
  284. }
  285. /// <summary>
  286. /// Adds a sort expression when Keyselector is provided but not Comparer
  287. /// </summary>
  288. internal void AddSortExpression<TKey>(Func<TRow, TKey> keySelector, bool isDescending, bool isOrderBy)
  289. {
  290. AddSortExpression<TKey>(keySelector, Comparer<TKey>.Default, isDescending, isOrderBy);
  291. }
  292. /// <summary>
  293. /// Adds a sort expression when Keyselector and Comparer are provided.
  294. /// </summary>
  295. internal void AddSortExpression<TKey>(
  296. Func<TRow, TKey> keySelector,
  297. IComparer<TKey> comparer,
  298. bool isDescending,
  299. bool isOrderBy)
  300. {
  301. DataSetUtil.CheckArgumentNull(keySelector, "keySelector");
  302. DataSetUtil.CheckArgumentNull(comparer, "comparer");
  303. _sortExpression.Add(
  304. delegate(TRow input)
  305. {
  306. return (object)keySelector(input);
  307. },
  308. delegate(object val1, object val2)
  309. {
  310. return (isDescending ? -1 : 1) * comparer.Compare((TKey)val1, (TKey)val2);
  311. },
  312. isOrderBy);
  313. }
  314. #endregion Add Single Filter/Sort Expression
  315. }
  316. }