PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/library/Library/CSListGeneric.cs

https://bitbucket.org/digitalizarte/coolstorage
C# | 3118 lines | 1632 code | 479 blank | 1007 comment | 113 complexity | e8dc0a6ce3948a29e781aa50817be43f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #region License
  2. //=============================================================================
  3. // Vici CoolStorage - .NET Object Relational Mapping Library
  4. //
  5. // Copyright (c) 2004-2009 Philippe Leybaert
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  23. // IN THE SOFTWARE.
  24. //=============================================================================
  25. #endregion
  26. using System;
  27. using System.Collections;
  28. using System.Collections.Generic;
  29. using System.ComponentModel;
  30. using System.Data;
  31. using System.Linq;
  32. using System.Reflection;
  33. using System.Runtime.Serialization;
  34. using Vici.Core;
  35. namespace Vici.CoolStorage
  36. {
  37. [Serializable]
  38. public class CSList<TObjectType> : CSList, ITypedList, IList<TObjectType>, IList, IBindingList, IListSource where TObjectType : CSObject<TObjectType>
  39. {
  40. private List<TObjectType> _objectArray;
  41. private List<TObjectType> _removedObjects; // Only used for pure many-to-many relations
  42. private List<TObjectType> _addedObjects; // Only used for pure many-to-many relations
  43. [NonSerialized]
  44. private Dictionary<object, TObjectType> _objectMap;
  45. [NonSerialized]
  46. private Predicate<TObjectType> _filterPredicate;
  47. [OnDeserializing]
  48. private void BeforeDeserializing(StreamingContext context)
  49. {
  50. Schema = CSSchema.Get(typeof(TObjectType));
  51. if (!string.IsNullOrEmpty(Schema.DefaultSortExpression))
  52. OrderBy = Schema.DefaultSortExpression;
  53. }
  54. [OnDeserialized]
  55. private void AfterDeserializing(StreamingContext context)
  56. {
  57. if (Schema.KeyColumns.Count == 1)
  58. {
  59. string columnName = Schema.KeyColumns[0].Name;
  60. _objectMap = new Dictionary<object, TObjectType>();
  61. foreach (TObjectType csObject in _objectArray)
  62. _objectMap.Add(csObject.Data["#" + columnName].Value, csObject);
  63. }
  64. }
  65. /// <summary>
  66. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class.
  67. /// </summary>
  68. public CSList()
  69. : base(CSSchema.Get(typeof(TObjectType)))
  70. {
  71. }
  72. /// <summary>
  73. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class using a filter.
  74. /// </summary>
  75. /// <param name="filterExpression">The filter expression.</param>
  76. public CSList(string filterExpression)
  77. : this(new CSFilter(filterExpression))
  78. {
  79. }
  80. public CSList(string filterExpression, object parameters)
  81. : this(filterExpression, new CSParameterCollection(parameters))
  82. {
  83. }
  84. public CSList(string filterExpression, string paramName, object paramValue)
  85. : this(filterExpression, new CSParameterCollection(paramName, paramValue))
  86. {
  87. }
  88. /// <summary>
  89. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class using a filter.
  90. /// </summary>
  91. /// <param name="filterExpression">The filter expression.</param>
  92. /// <param name="paramName1">The param name1.</param>
  93. /// <param name="paramValue1">The param value1.</param>
  94. /// <param name="paramName2">The param name2.</param>
  95. /// <param name="paramValue2">The param value2.</param>
  96. public CSList(string filterExpression, string paramName1, object paramValue1, string paramName2, object paramValue2)
  97. : this(filterExpression, new CSParameterCollection(paramName1, paramValue1, paramName2, paramValue2))
  98. {
  99. }
  100. /// <summary>
  101. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class using a filter.
  102. /// </summary>
  103. /// <param name="filterExpression">The filter expression.</param>
  104. /// <param name="paramName1">The param name1.</param>
  105. /// <param name="paramValue1">The param value1.</param>
  106. /// <param name="paramName2">The param name2.</param>
  107. /// <param name="paramValue2">The param value2.</param>
  108. /// <param name="paramName3">The param name3.</param>
  109. /// <param name="paramValue3">The param value3.</param>
  110. public CSList(string filterExpression, string paramName1, object paramValue1, string paramName2, object paramValue2, string paramName3, object paramValue3)
  111. : this(filterExpression, new CSParameterCollection(paramName1, paramValue1, paramName2, paramValue2, paramName3, paramValue3))
  112. {
  113. }
  114. /// <summary>
  115. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class using a filter.
  116. /// </summary>
  117. /// <param name="filterExpression">The filter expression.</param>
  118. /// <param name="parameters">The parameters.</param>
  119. public CSList(string filterExpression, CSParameterCollection parameters)
  120. : this(new CSFilter(filterExpression, parameters))
  121. {
  122. }
  123. /// <summary>
  124. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class using a filter.
  125. /// </summary>
  126. /// <param name="filterExpression">The filter expression.</param>
  127. /// <param name="parameters">The parameters.</param>
  128. public CSList(string filterExpression, params CSParameter[] parameters)
  129. : this(new CSFilter(filterExpression, parameters))
  130. {
  131. }
  132. /// <summary>
  133. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class using a filter.
  134. /// </summary>
  135. /// <param name="filter">The filter.</param>
  136. public CSList(CSFilter filter)
  137. : this()
  138. {
  139. Filter = filter;
  140. }
  141. /// <summary>
  142. /// Initializes a new instance of the <see cref="CSList&lt;TEntity&gt;"/> class given a CSList of the same type.
  143. /// </summary>
  144. /// <param name="sourceCollection">The source collection.</param>
  145. public CSList(CSList<TObjectType> sourceCollection)
  146. : this()
  147. {
  148. OrderBy = sourceCollection.OrderBy;
  149. MaxRecords = sourceCollection.MaxRecords;
  150. StartRecord = sourceCollection.StartRecord;
  151. Filter = sourceCollection.Filter;
  152. FilterPredicate = sourceCollection.FilterPredicate;
  153. Relation = sourceCollection.Relation;
  154. RelationObject = sourceCollection.RelationObject;
  155. PrefetchPaths = sourceCollection.PrefetchPaths;
  156. }
  157. /// <summary>
  158. /// Gets or sets the element at the specified index.
  159. /// </summary>
  160. /// <returns>
  161. /// The element at the specified index.
  162. /// </returns>
  163. ///
  164. /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
  165. /// </exception>
  166. ///
  167. /// <exception cref="T:System.NotSupportedException">
  168. /// The property is set and the <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
  169. /// </exception>
  170. public TObjectType this[int i]
  171. {
  172. get
  173. {
  174. Populate();
  175. return _objectArray[i];
  176. }
  177. set
  178. {
  179. throw new NotSupportedException();
  180. }
  181. }
  182. /// <summary>
  183. /// Represents a new CSList generated from this list.
  184. /// </summary>
  185. /// <param name="filter">The filter.</param>
  186. /// <returns>
  187. /// This CSList fltered.
  188. /// </returns>
  189. public CSList<TObjectType> Where(CSFilter filter)
  190. {
  191. return FilteredBy(filter);
  192. }
  193. /// <summary>
  194. /// Represents a new CSList generated from this list.
  195. /// </summary>
  196. /// <param name="filter">The filter.</param>
  197. /// <returns>
  198. /// This CSList fltered.
  199. /// </returns>
  200. public CSList<TObjectType> Where(string filter)
  201. {
  202. return FilteredBy(new CSFilter(filter));
  203. }
  204. /// <summary>
  205. /// Represents a new CSList generated from this list.
  206. /// </summary>
  207. /// <param name="filter">The filter.</param>
  208. /// <param name="parameters">The parameters.</param>
  209. /// <returns>
  210. /// This CSList fltered.
  211. /// </returns>
  212. public CSList<TObjectType> Where(string filter, CSParameterCollection parameters)
  213. {
  214. return FilteredBy(new CSFilter(filter, parameters));
  215. }
  216. /// <summary>
  217. /// Represents a new CSList generated from this list.
  218. /// </summary>
  219. /// <param name="filter">The filter.</param>
  220. /// <param name="parameters">The parameters.</param>
  221. /// <returns>
  222. /// This CSList fltered.
  223. /// </returns>
  224. public CSList<TObjectType> Where(string filter, params CSParameter[] parameters)
  225. {
  226. return FilteredBy(new CSFilter(filter, parameters));
  227. }
  228. public CSList<TObjectType> Where(string filter, object parameters)
  229. {
  230. return FilteredBy(new CSFilter(filter, parameters));
  231. }
  232. /// <summary>
  233. /// Represents a new CSList generated from this list.
  234. /// </summary>
  235. /// <param name="filter">The filter.</param>
  236. /// <param name="paramName">Name of the param.</param>
  237. /// <param name="paramValue">The param value.</param>
  238. /// <returns>
  239. /// This CSList fltered.
  240. /// </returns>
  241. public CSList<TObjectType> Where(string filter, string paramName, object paramValue)
  242. {
  243. return FilteredBy(new CSFilter(filter, paramName, paramValue));
  244. }
  245. /// <summary>
  246. /// Represents a new CSList generated from this list.
  247. /// </summary>
  248. /// <param name="filter">The filter.</param>
  249. /// <param name="paramName1">The param name1.</param>
  250. /// <param name="paramValue1">The param value1.</param>
  251. /// <param name="paramName2">The param name2.</param>
  252. /// <param name="paramValue2">The param value2.</param>
  253. /// <returns>
  254. /// This CSList fltered.
  255. /// </returns>
  256. public CSList<TObjectType> Where(string filter, string paramName1, object paramValue1, string paramName2, object paramValue2)
  257. {
  258. return FilteredBy(new CSFilter(filter, paramName1, paramValue1, paramName2, paramValue2));
  259. }
  260. /// <summary>
  261. /// Represents a new CSList generated from this list.
  262. /// </summary>
  263. /// <param name="filter">The filter.</param>
  264. /// <param name="paramName1">The param name1.</param>
  265. /// <param name="paramValue1">The param value1.</param>
  266. /// <param name="paramName2">The param name2.</param>
  267. /// <param name="paramValue2">The param value2.</param>
  268. /// <param name="paramName3">The param name3.</param>
  269. /// <param name="paramValue3">The param value3.</param>
  270. /// <returns>
  271. /// This CSList fltered.
  272. /// </returns>
  273. public CSList<TObjectType> Where(string filter, string paramName1, object paramValue1, string paramName2, object paramValue2, string paramName3, object paramValue3)
  274. {
  275. return FilteredBy(new CSFilter(filter, paramName1, paramValue1, paramName2, paramValue2, paramName3, paramValue3));
  276. }
  277. /// <summary>
  278. /// Represents a new CSList generated from this list.
  279. /// </summary>
  280. /// <param name="predicate">The predicate.</param>
  281. /// <returns>
  282. /// This CSList fltered.
  283. /// </returns>
  284. public CSList<TObjectType> Where(Predicate<TObjectType> predicate)
  285. {
  286. return FilteredBy(predicate);
  287. }
  288. public CSList<TObjectType> FilteredBy(CSFilter filter)
  289. {
  290. CSList<TObjectType> newCollection = Clone();
  291. newCollection.Filter = Filter.And(filter);
  292. return newCollection;
  293. }
  294. public CSList<TObjectType> FilteredBy(string filter)
  295. {
  296. return FilteredBy(new CSFilter(filter));
  297. }
  298. public CSList<TObjectType> FilteredBy(string filter, CSParameterCollection parameters)
  299. {
  300. return FilteredBy(new CSFilter(filter, parameters));
  301. }
  302. public CSList<TObjectType> FilteredBy(string filter, params CSParameter[] parameters)
  303. {
  304. return FilteredBy(new CSFilter(filter, parameters));
  305. }
  306. public CSList<TObjectType> FilteredBy(string filter, object parameters)
  307. {
  308. return FilteredBy(new CSFilter(filter, parameters));
  309. }
  310. public CSList<TObjectType> FilteredBy(string filter, string paramName, object paramValue)
  311. {
  312. return FilteredBy(new CSFilter(filter, paramName, paramValue));
  313. }
  314. public CSList<TObjectType> FilteredBy(string filter, string paramName1, object paramValue1, string paramName2, object paramValue2)
  315. {
  316. return FilteredBy(new CSFilter(filter, paramName1, paramValue1, paramName2, paramValue2));
  317. }
  318. public CSList<TObjectType> FilteredBy(string filter, string paramName1, object paramValue1, string paramName2, object paramValue2, string paramName3, object paramValue3)
  319. {
  320. return FilteredBy(new CSFilter(filter, paramName1, paramValue1, paramName2, paramValue2, paramName3, paramValue3));
  321. }
  322. public CSList<TObjectType> FilteredBy(Predicate<TObjectType> predicate)
  323. {
  324. CSList<TObjectType> newCollection = Clone();
  325. newCollection.FilterPredicate += predicate;
  326. return newCollection;
  327. }
  328. public CSList<TObjectType> OrderedBy(string orderBy)
  329. {
  330. CSList<TObjectType> newCollection = Clone();
  331. newCollection.OrderBy = orderBy;
  332. return newCollection;
  333. }
  334. public CSList<TObjectType> ThenBy(string orderBy)
  335. {
  336. if (string.IsNullOrEmpty(OrderBy))
  337. throw new CSException(".ThenBy() called without .OrderedBy()");
  338. CSList<TObjectType> newCollection = Clone();
  339. newCollection.OrderBy += "," + orderBy;
  340. return newCollection;
  341. }
  342. public CSList<TObjectType> Range(int from, int numRecords)
  343. {
  344. CSList<TObjectType> newCollection = Clone();
  345. newCollection.MaxRecords = numRecords;
  346. newCollection.StartRecord = from;
  347. return newCollection;
  348. }
  349. public CSList<TObjectType> LimitTo(int numRecords)
  350. {
  351. CSList<TObjectType> newCollection = Clone();
  352. newCollection.MaxRecords = numRecords;
  353. return newCollection;
  354. }
  355. public CSList<TObjectType> WithPrefetch(params string[] prefetchPaths)
  356. {
  357. CSList<TObjectType> newCollection = Clone();
  358. newCollection.PrefetchPaths = prefetchPaths;
  359. return newCollection;
  360. }
  361. private CSList<TObjectType> Clone()
  362. {
  363. CSList<TObjectType> newCollection = (CSList<TObjectType>)Activator.CreateInstance(GetType());
  364. newCollection.OrderBy = OrderBy;
  365. newCollection.MaxRecords = MaxRecords;
  366. newCollection.StartRecord = StartRecord;
  367. newCollection.FilterPredicate = FilterPredicate;
  368. newCollection.Filter = Filter;
  369. newCollection.Relation = Relation;
  370. newCollection.RelationObject = RelationObject;
  371. newCollection.PrefetchPaths = newCollection.PrefetchPaths;
  372. return newCollection;
  373. }
  374. protected TObjectType GetByKey(object key)
  375. {
  376. Populate();
  377. if (_objectMap != null && _objectMap.ContainsKey(key))
  378. return _objectMap[key];
  379. return null;
  380. }
  381. public override int Count
  382. {
  383. get
  384. {
  385. Populate();
  386. return _objectArray.Count;
  387. }
  388. }
  389. public override int CountFast
  390. {
  391. get
  392. {
  393. if (Populated)
  394. return _objectArray.Count;
  395. return GetScalar("*", CSAggregate.Count).Convert<int>();
  396. }
  397. }
  398. public override void Refresh()
  399. {
  400. Populated = false;
  401. _objectArray = null;
  402. _objectMap = null;
  403. #if !WINDOWS_PHONE && !SILVERLIGHT
  404. if (ListChanged != null)
  405. ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1));
  406. #endif
  407. }
  408. public override bool Save()
  409. {
  410. if (!Populated)
  411. return true;
  412. using (CSTransaction csTransaction = new CSTransaction(Schema, IsolationLevel.ReadUncommitted))
  413. {
  414. UpdateForeignKeys();
  415. foreach (TObjectType obj in _objectArray.ToArray())
  416. {
  417. if (obj.IsDirty)
  418. if (!obj.Save())
  419. return false;
  420. }
  421. if (Relation != null && Relation.PureManyToMany)
  422. {
  423. if (_removedObjects != null)
  424. {
  425. foreach (TObjectType obj in _removedObjects)
  426. {
  427. CSParameterCollection parameters = new CSParameterCollection();
  428. parameters.Add("@LocalKey").Value = RelationObject.Data["#" + Relation.LocalKey].Value;
  429. parameters.Add("@ForeignKey").Value = obj.Data["#" + Relation.ForeignKey].Value;
  430. string deleteSql = DB.BuildDeleteSQL(Relation.LinkTable, null, DB.QuoteField(Relation.LocalLinkKey) + "=@LocalKey and " + DB.QuoteField(Relation.ForeignLinkKey) + "=@ForeignKey");
  431. DB.ExecuteNonQuery(deleteSql, parameters);
  432. }
  433. _removedObjects = null;
  434. }
  435. if (_addedObjects != null)
  436. {
  437. foreach (TObjectType obj in _addedObjects)
  438. {
  439. CSParameterCollection parameters = new CSParameterCollection();
  440. parameters.Add("@LocalKey").Value = RelationObject.Data["#" + Relation.LocalKey].Value;
  441. parameters.Add("@ForeignKey").Value = obj.Data["#" + Relation.ForeignKey].Value;
  442. DB.ExecuteInsert(Relation.LinkTable,
  443. new[] { Relation.LocalLinkKey, Relation.ForeignLinkKey },
  444. new[] { "@LocalKey", "@ForeignKey" },
  445. null, null, null, parameters);
  446. // string insertSql =
  447. // DB.BuildInsertSQL(Relation.LinkTable,
  448. // new[] { Relation.LocalLinkKey, Relation.ForeignLinkKey },
  449. // new[] { "@LocalKey", "@ForeignKey" },
  450. // null, null, null);
  451. //DB.ExecuteNonQuery(insertSql, parameters);
  452. }
  453. }
  454. }
  455. csTransaction.Commit();
  456. return true;
  457. }
  458. }
  459. public TObjectType UniqueItem
  460. {
  461. get
  462. {
  463. Populate();
  464. if (Count > 1)
  465. throw new CSException("UniqueItem expects 0 or 1 items in list");
  466. if (Count == 1)
  467. return _objectArray[0];
  468. return null;
  469. }
  470. }
  471. public TObjectType FirstItem
  472. {
  473. get
  474. {
  475. Populate();
  476. return Count == 0 ? null : _objectArray[0];
  477. }
  478. }
  479. public object GetScalar(string fieldName, CSAggregate aggregate)
  480. {
  481. return GetScalar(fieldName, aggregate, null, null);
  482. }
  483. public object GetScalar(string fieldName, string orderBy)
  484. {
  485. return GetScalar(fieldName, orderBy, null, null);
  486. }
  487. public object GetScalar(string fieldName, string orderBy, string filterExpression)
  488. {
  489. return GetScalar(fieldName, orderBy, filterExpression, null);
  490. }
  491. public object GetScalar(string fieldName, string orderBy, string filterExpression, string paramName, object paramValue)
  492. {
  493. return GetScalar(fieldName, orderBy, filterExpression, new CSParameterCollection(paramName, paramValue));
  494. }
  495. public object GetScalar(string fieldName, string orderBy, string filterExpression, CSParameterCollection filterParameters)
  496. {
  497. string tableAlias = CSNameGenerator.NextTableAlias;
  498. CSFilter queryFilter = Filter.And(BuildRelationFilter(tableAlias));
  499. if (!string.IsNullOrEmpty(filterExpression))
  500. {
  501. queryFilter = queryFilter.And(filterExpression, filterParameters);
  502. }
  503. return CSObject<TObjectType>.GetScalar(fieldName, tableAlias, orderBy, queryFilter);
  504. }
  505. public object GetScalar(string fieldName, CSAggregate aggregate, string filterExpression, CSParameterCollection filterParameters)
  506. {
  507. string tableAlias = CSNameGenerator.NextTableAlias;
  508. CSFilter queryFilter = Filter.And(BuildRelationFilter(tableAlias));
  509. if (!string.IsNullOrEmpty(filterExpression))
  510. {
  511. queryFilter = queryFilter.And(filterExpression, filterParameters);
  512. }
  513. return CSObject<TObjectType>.GetScalar(fieldName, tableAlias, aggregate, queryFilter);
  514. }
  515. public object GetScalar(string fieldName, CSAggregate aggregate, string filterExpression)
  516. {
  517. return GetScalar(fieldName, aggregate, filterExpression, null);
  518. }
  519. public object GetScalar(string fieldName, CSAggregate aggregate, string filterExpression, object parameters)
  520. {
  521. return GetScalar(fieldName, aggregate, filterExpression, new CSParameterCollection(parameters));
  522. }
  523. public object GetScalar(string fieldName, CSAggregate aggregate, string filterExpression, string paramName, object paramValue)
  524. {
  525. return GetScalar(fieldName, aggregate, filterExpression, new CSParameterCollection(paramName, paramValue));
  526. }
  527. public bool DeleteAll()
  528. {
  529. Populate();
  530. List<TObjectType> toDeleteList = new List<TObjectType>();
  531. foreach (TObjectType obj in _objectArray)
  532. toDeleteList.Add(obj);
  533. foreach (TObjectType obj in toDeleteList)
  534. if (!obj.Delete())
  535. return false;
  536. return true;
  537. }
  538. public bool DeleteAll(Predicate<TObjectType> predicate)
  539. {
  540. Populate();
  541. List<TObjectType> toDeleteList = new List<TObjectType>();
  542. foreach (TObjectType obj in _objectArray)
  543. if (predicate(obj))
  544. toDeleteList.Add(obj);
  545. foreach (TObjectType obj in toDeleteList)
  546. if (!obj.Delete())
  547. return false;
  548. return true;
  549. }
  550. public TObjectType AddNew()
  551. {
  552. TObjectType obj = CSObject<TObjectType>.New();
  553. Add(obj);
  554. return obj;
  555. }
  556. public void Add(TObjectType obj)
  557. {
  558. Populate();
  559. if (Relation != null && (Relation.RelationType == CSSchemaRelationType.ManyToMany && !Relation.PureManyToMany))
  560. throw new NotSupportedException("CSList.Add() not supported for non-pure Many-To-Many relations");
  561. if (Relation != null && Relation.PureManyToMany)
  562. {
  563. if (_addedObjects == null)
  564. _addedObjects = new List<TObjectType>();
  565. _addedObjects.Add(obj);
  566. }
  567. obj.ObjectDeleted += OnObjectDeleted;
  568. _objectArray.Add(obj);
  569. #if !WINDOWS_PHONE && !SILVERLIGHT
  570. if (ListChanged != null)
  571. ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemAdded, _objectArray.Count - 1));
  572. #endif
  573. }
  574. public void AddRange(IEnumerable<TObjectType> range)
  575. {
  576. foreach (TObjectType obj in range)
  577. Add(obj);
  578. }
  579. public void Remove(TObjectType value)
  580. {
  581. Populate();
  582. int idx = _objectArray.IndexOf(value);
  583. if (idx >= 0)
  584. RemoveAt(idx);
  585. }
  586. private CSDataProvider DB
  587. {
  588. get
  589. {
  590. return Schema.DB;
  591. }
  592. }
  593. public void ForEach(Action<TObjectType> action)
  594. {
  595. Populate();
  596. foreach (TObjectType obj in _objectArray)
  597. action(obj);
  598. }
  599. public TObjectType Find(TObjectType obj)
  600. {
  601. int idx = IndexOf(obj);
  602. return idx >= 0 ? this[idx] : null;
  603. }
  604. public TObjectType Find(Predicate<TObjectType> predicate)
  605. {
  606. Populate();
  607. return _objectArray.FirstOrDefault(o => predicate(o));
  608. }
  609. public bool Contains(Predicate<TObjectType> predicate)
  610. {
  611. return Find(predicate) != null;
  612. }
  613. private void Populate()
  614. {
  615. if (Populated)
  616. return;
  617. if (Relation != null && RelationObject != null && Relation.RelationType == CSSchemaRelationType.OneToMany && RelationObject.IsNew)
  618. {
  619. _objectArray = new List<TObjectType>();
  620. Populated = true;
  621. return;
  622. }
  623. CSTable table = new CSTable(Schema);
  624. //string mainAlias = CSHelper.NextTableAlias;
  625. List<string> columnList = new List<string>(Schema.ColumnsToRead.Count);
  626. List<string> aliasList = new List<string>(Schema.ColumnsToRead.Count);
  627. Dictionary<string, string> aliasMap = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
  628. foreach (string columnName in Schema.ColumnsToRead)
  629. {
  630. string alias = CSNameGenerator.NextFieldAlias;
  631. columnList.Add(table.TableAlias + "." + columnName);
  632. aliasList.Add(alias);
  633. aliasMap.Add(alias, columnName);
  634. }
  635. CSJoinList filterJoins = new CSJoinList();
  636. List<PrefetchField> prefetchFields = CSObject.GetPrefetchFieldsOne(table, columnList, aliasList, filterJoins, PrefetchPaths);
  637. CSFilter whereFilter;
  638. if (PrefetchFilter != null)
  639. {
  640. whereFilter = new CSFilter(DB.QuoteField(table.TableAlias + "." + PrefetchFilter.ForeignKey) + " in (" + PrefetchFilter.InStatement + ")", PrefetchFilter.Parameters);
  641. }
  642. else
  643. {
  644. string parsedFilterExpression = CSExpressionParser.ParseFilter(Filter.Expression, Schema, table.TableAlias, filterJoins);
  645. whereFilter = new CSFilter(parsedFilterExpression, Filter.Parameters);
  646. CSFilter relationFilter = BuildRelationFilter(table.TableAlias);
  647. whereFilter = whereFilter.And(CSExpressionParser.ParseFilter(relationFilter.Expression, Schema, table.TableAlias, filterJoins), relationFilter.Parameters);
  648. }
  649. string parsedOrderBy = CSExpressionParser.ParseOrderBy(OrderBy, Schema, table.TableAlias, filterJoins);
  650. string sqlQuery = DB.BuildSelectSQL(table.TableName, table.TableAlias, columnList.ToArray(), aliasList.ToArray(), filterJoins.BuildJoinExpressions(), whereFilter.Expression, parsedOrderBy, StartRecord, MaxRecords, true, false);
  651. _objectArray = GetObjects(sqlQuery, whereFilter.Parameters, aliasMap, prefetchFields);
  652. if (Schema.KeyColumns.Count == 1)
  653. {
  654. string columnName = Schema.KeyColumns[0].Name;
  655. _objectMap = new Dictionary<object, TObjectType>();
  656. foreach (TObjectType csObject in _objectArray)
  657. _objectMap.Add(csObject.Data["#" + columnName].Value, csObject);
  658. }
  659. foreach (CSSchemaField prefetchField in GetPrefetchFieldsMany())
  660. {
  661. CSRelation relation = prefetchField.Relation;
  662. Dictionary<object, TObjectType> prefetchMap = new Dictionary<object, TObjectType>();
  663. // Creates empty lists in each object of this list
  664. foreach (TObjectType csObject in _objectArray)
  665. {
  666. prefetchMap[csObject.Data["#" + relation.LocalKey].Value] = csObject;
  667. CSList relationCollection = (CSList)Activator.CreateInstance(prefetchField.FieldType);
  668. relationCollection.Relation = relation;
  669. relationCollection.RelationObject = csObject;
  670. relationCollection.InitializePrefetch();
  671. csObject.Data[prefetchField.Name].ValueDirect = relationCollection;
  672. csObject.Data[prefetchField.Name].ValueState = CSFieldValueState.Read;
  673. }
  674. Type objectType = relation.ForeignSchema.ClassType;
  675. CSList csList = (CSList)Activator.CreateInstance(typeof(CSList<>).MakeGenericType(objectType));
  676. //string prefetchTableAlias = CSNameGenerator.NextTableAlias;
  677. List<string> joinsList = new List<string>();
  678. relation.LocalKeys.ForEach(localKey => joinsList.Add(String.Format("{0}.{1}", table.TableAlias, localKey)));
  679. //string prefetchFilter = DB.BuildSelectSQL(table.TableName, table.TableAlias, new[] { table.TableAlias + "." + relation.LocalKey }, new[] { CSNameGenerator.NextFieldAlias }, filterJoins.BuildJoinExpressions(), whereFilter.Expression, parsedOrderBy, StartRecord, MaxRecords, true, true);
  680. string prefetchFilter = DB.BuildSelectSQL(table.TableName, table.TableAlias, joinsList.ToArray(), new[] { CSNameGenerator.NextFieldAlias }, filterJoins.BuildJoinExpressions(), whereFilter.Expression, parsedOrderBy, StartRecord, MaxRecords, true, true);
  681. csList.PrefetchFilter = new PrefetchFilter(relation.ForeignKey, prefetchFilter, whereFilter.Parameters);
  682. if (PrefetchPaths != null && PrefetchPaths.Length > 0)
  683. {
  684. List<string> newPrefetchPaths = new List<string>();
  685. foreach (string path in PrefetchPaths)
  686. {
  687. if (path.StartsWith(prefetchField.Name + "."))
  688. {
  689. newPrefetchPaths.Add(path.Substring(prefetchField.Name.Length + 1));
  690. }
  691. }
  692. if (newPrefetchPaths.Count > 0)
  693. csList.PrefetchPaths = newPrefetchPaths.ToArray();
  694. }
  695. foreach (CSObject csObject in csList)
  696. {
  697. //object localKey = csObject.Data[String.Format("#{0}", relation.ForeignKey)].ValueDirect;
  698. string localKey = "";
  699. relation.ForeignKeys.ForEach(foreignKey =>
  700. {
  701. localKey += Convert.ToString(csObject.Data[String.Format("#{0}", foreignKey)].ValueDirect);
  702. });
  703. CSList relationCollection = (CSList)prefetchMap[localKey].Data[prefetchField.Name].ValueDirect;
  704. relationCollection.AddFromPrefetch(csObject);
  705. }
  706. }
  707. Populated = true;
  708. }
  709. internal override void AddFromPrefetch(CSObject csObject)
  710. {
  711. csObject.Fire_ObjectReading();
  712. ((TObjectType)csObject).ObjectDeleted += OnObjectDeleted;
  713. _objectArray.Add((TObjectType)csObject);
  714. csObject.Fire_ObjectRead();
  715. }
  716. internal override void InitializePrefetch()
  717. {
  718. Populated = true;
  719. _objectArray = new List<TObjectType>();
  720. }
  721. private List<TObjectType> GetObjects(string sqlQuery, CSParameterCollection parameters, Dictionary<string, string> aliasMap, IEnumerable<PrefetchField> prefetchFields)
  722. {
  723. using (CSTransaction csTransaction = new CSTransaction(Schema))
  724. {
  725. List<TObjectType> objectList = new List<TObjectType>();
  726. using (ICSDbReader reader = DB.CreateReader(sqlQuery, parameters))
  727. {
  728. int recs = 0;
  729. bool ok = true;
  730. while (recs == 0 && ok)
  731. {
  732. while (reader.Read())
  733. {
  734. TObjectType csObject = CSObject<TObjectType>.New();
  735. csObject.Fire_ObjectReading();
  736. csObject.FromDataReader(reader, aliasMap);
  737. foreach (PrefetchField prefetchField in prefetchFields)
  738. csObject.ReadRelationToOne(prefetchField.SchemaField, reader, prefetchField.AliasMap);
  739. if (FilterPredicate != null)
  740. {
  741. bool shouldAdd = true;
  742. foreach (Predicate<TObjectType> predicate in FilterPredicate.GetInvocationList())
  743. if (!predicate(csObject))
  744. {
  745. shouldAdd = false;
  746. break;
  747. }
  748. if (!shouldAdd)
  749. continue;
  750. }
  751. csObject.ObjectDeleted += OnObjectDeleted;
  752. objectList.Add(csObject);
  753. csObject.Fire_ObjectRead();
  754. recs++;
  755. }
  756. ok = reader.NextResult();
  757. }
  758. }
  759. csTransaction.Commit();
  760. return objectList;
  761. }
  762. }
  763. internal override void UpdateForeignKeys()
  764. {
  765. if (!Populated || Relation == null)
  766. return;
  767. //2010-12-13 DAE-BER Cambiamos la condición para que no entre e itere si no es necesario.
  768. if (Relation.RelationType == CSSchemaRelationType.OneToMany)
  769. {
  770. foreach (TObjectType obj in _objectArray)
  771. {
  772. //TODO Modificar para Claves Compuestas
  773. //CSFieldValue parentValue = RelationObject.Data["#" + Relation.LocalKey];
  774. //CSFieldValue thisValue = obj.Data["#" + Relation.ForeignKey];
  775. //if (obj.IsNew || thisValue.Value == null || !thisValue.Value.Equals(parentValue.Value))
  776. // if (Relation.RelationType == CSSchemaRelationType.OneToMany)
  777. // thisValue.Value = parentValue.Value;
  778. for (int i = 0; i < Relation.LocalKeys.Count; i++)
  779. {
  780. CSFieldValue parentValue = RelationObject.Data[String.Format("#{0}", Relation.LocalKeys[i])];
  781. CSFieldValue thisValue = obj.Data[String.Format("#{0}", Relation.ForeignKeys[i])];
  782. if (obj.IsNew || thisValue.Value == null || !thisValue.Value.Equals(parentValue.Value))
  783. if (Relation.RelationType == CSSchemaRelationType.OneToMany)
  784. thisValue.Value = parentValue.Value;
  785. }
  786. }
  787. }}
  788. private void OnObjectDeleted(TObjectType sender, EventArgs e)
  789. {
  790. int idx = _objectArray.IndexOf(sender);
  791. if (idx >= 0)
  792. _objectArray.RemoveAt(idx);
  793. }
  794. public TObjectType[] ToArray()
  795. {
  796. Populate();
  797. return _objectArray.ToArray();
  798. }
  799. public T[] ToArray<T>(Converter<TObjectType, T> converter)
  800. {
  801. Populate();
  802. T[] array = new T[Count];
  803. for (int i = 0; i < Count; i++)
  804. {
  805. array[i] = converter(_objectArray[i]);
  806. }
  807. return array;
  808. }
  809. public List<TObjectType> ToList()
  810. {
  811. Populate();
  812. return new List<TObjectType>(_objectArray);
  813. }
  814. public List<T> ToList<T>(Converter<TObjectType, T> converter)
  815. {
  816. Populate();
  817. List<T> array = new List<T>(Count);
  818. for (int i = 0; i < Count; i++)
  819. array.Add(converter(_objectArray[i]));
  820. return array;
  821. }
  822. #region IList Members
  823. public bool IsReadOnly
  824. {
  825. get
  826. {
  827. return false;
  828. }
  829. }
  830. object IList.this[int index]
  831. {
  832. get
  833. {
  834. Populate();
  835. return _objectArray[index];
  836. }
  837. set
  838. {
  839. throw new CSException("Items in CSCollections can not be set");
  840. }
  841. }
  842. public void RemoveAt(int index)
  843. {
  844. Populate();
  845. if (Relation != null && Relation.PureManyToMany)
  846. {
  847. if (_removedObjects == null)
  848. _removedObjects = new List<TObjectType>();
  849. _removedObjects.Add(_objectArray[index]);
  850. }
  851. _objectArray.RemoveAt(index);
  852. #if !WINDOWS_PHONE && !SILVERLIGHT
  853. if (ListChanged != null)
  854. ListChanged(this, new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
  855. #endif
  856. }
  857. public void RemoveAll()
  858. {
  859. Populate();
  860. if (Relation != null && Relation.PureManyToMany)
  861. {
  862. _removedObjects = new List<TObjectType>(_objectArray);
  863. }
  864. _objectArray.Clear();
  865. }
  866. public void RemoveAll(Predicate<TObjectType> predicate)
  867. {
  868. Populate();
  869. if (Relation != null && Relation.PureManyToMany)
  870. {
  871. _removedObjects = new List<TObjectType>();
  872. foreach (TObjectType obj in _objectArray)
  873. if (predicate(obj))
  874. _removedObjects.Add(obj);
  875. foreach (TObjectType obj in _removedObjects)
  876. _objectArray.Remove(obj);
  877. }
  878. else
  879. {
  880. _objectArray.RemoveAll(predicate);
  881. }
  882. }
  883. public void Insert(int index, CSObject value)
  884. {
  885. throw new NotSupportedException("Insert() not supported for CSList");
  886. }
  887. void IList.Insert(int index, object value)
  888. {
  889. throw new NotSupportedException("Insert() not supported for CSList");
  890. }
  891. internal override void Remove(CSObject obj)
  892. {
  893. Remove((TObjectType)obj);
  894. }
  895. void IList.Remove(object value)
  896. {
  897. Remove((TObjectType)value);
  898. }
  899. public bool Contains(TObjectType value)
  900. {
  901. Populate();
  902. return _objectArray.Contains(value);
  903. }
  904. bool IList.Contains(object value)
  905. {
  906. Populate();
  907. return _objectArray.Contains((TObjectType)value);
  908. }
  909. public void Clear()
  910. {
  911. throw new NotSupportedException("Clear() not supported for CSList");
  912. }
  913. int IList.IndexOf(object value)
  914. {
  915. Populate();
  916. return _objectArray.IndexOf((TObjectType)value);
  917. }
  918. /// <summary>
  919. /// Dados dos CSObject de un tipo dado, devuelve si tienen la misma PK
  920. /// </summary>
  921. /// <param name="o1"></param>
  922. /// <param name="o2"></param>
  923. /// <returns></returns>
  924. public bool EqualsByPK(TObjectType o1, TObjectType o2) {
  925. foreach (CSSchemaColumn c in o1.Schema.KeyColumns) {
  926. if (!o1.Data[c.Name].Value.Equals(o2.Data[c.Name].Value))
  927. return false;
  928. }
  929. return true;
  930. }
  931. /// <summary>
  932. /// Devuelve el índice en la lista de un objeto dado en caso de que coincida la PK
  933. /// </summary>
  934. /// <param name="value"></param>
  935. /// <returns></returns>
  936. public int IndexOfByPK(TObjectType value) {
  937. TObjectType r = FindByPK(value);
  938. if (r != null)
  939. return this.IndexOf(r);
  940. else
  941. return -1;
  942. }
  943. /// <summary>
  944. /// Obtiene un objeto de la CSLIst por PK del objeto pasado
  945. /// </summary>
  946. /// <returns></returns>
  947. public TObjectType FindByPK(TObjectType value)
  948. {
  949. Populate();
  950. TObjectType r = this.Find(delegate(TObjectType x)
  951. {
  952. return EqualsByPK(x, value);
  953. });
  954. return r;
  955. }
  956. /// <summary>
  957. ///
  958. /// </summary>
  959. /// <param name="value"></param>
  960. /// <returns></returns>
  961. public int IndexOf(TObjectType value)
  962. {
  963. Populate();
  964. return _objectArray.IndexOf(value);
  965. }
  966. int IList.Add(object value)
  967. {
  968. Populate();
  969. if (value is TObjectType)
  970. Add((TObjectType)value);
  971. else
  972. throw new CSException("Add() only supported for objects of type <" + typeof(TObjectType).Name + ">");
  973. return _objectArray.Count - 1;
  974. }
  975. public bool IsFixedSize
  976. {
  977. get
  978. {
  979. return false;
  980. }
  981. }
  982. #endregion
  983. #region ICollection Members
  984. public bool IsSynchronized
  985. {
  986. get
  987. {
  988. return false;
  989. }
  990. }
  991. public void CopyTo(TObjectType[] array, int index)
  992. {
  993. Populate();
  994. _objectArray.CopyTo(array, index);
  995. }
  996. void ICollection.CopyTo(Array array, int index)
  997. {
  998. Populate();
  999. _objectArray.CopyTo((TObjectType[])array, index);
  1000. }
  1001. public object SyncRoot
  1002. {
  1003. get
  1004. {
  1005. Populate();
  1006. return _objectArray;
  1007. }
  1008. }
  1009. #endregion
  1010. internal Predicate<TObjectType> FilterPredicate
  1011. {
  1012. get { return _filterPredicate; }
  1013. set { _filterPredicate = value; }
  1014. }
  1015. #if !WINDOWS_PHONE && !SILVERLIGHT
  1016. #region ITypedList Members
  1017. public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
  1018. {
  1019. List<PropertyDescriptor> descriptors = new List<PropertyDescriptor>();
  1020. PropertyInfo[] properties = typeof(TObjectType).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  1021. foreach (PropertyInfo propertyInfo in properties)
  1022. descriptors.Add(new CSFieldDescriptor(typeof(TObjectType), propertyInfo));
  1023. return new PropertyDescriptorCollection(descriptors.ToArray());
  1024. }
  1025. public string GetListName(PropertyDescriptor[] listAccessors)
  1026. {
  1027. return "CSList_" + typeof(TObjectType).Name;
  1028. }
  1029. #endregion
  1030. #region IBindingList Members
  1031. public void AddIndex(PropertyDescriptor property)
  1032. {
  1033. }
  1034. public bool AllowNew
  1035. {
  1036. get
  1037. {
  1038. return true;
  1039. }
  1040. }
  1041. public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
  1042. {
  1043. OrderBy = property.Name;
  1044. if (direction == ListSortDirection.Descending)
  1045. OrderBy += "-";
  1046. Refresh();
  1047. }
  1048. public PropertyDescriptor SortProperty
  1049. {
  1050. get
  1051. {
  1052. string[] arr = OrderBy.Split(' ');
  1053. return arr.Length > 0 ? GetItemProperties(null)[arr[0]] : null;
  1054. }
  1055. }
  1056. public int Find(PropertyDescriptor property, object key)
  1057. {
  1058. throw new NotSupportedException();
  1059. }
  1060. public bool SupportsSorting
  1061. {
  1062. get
  1063. {
  1064. return true;
  1065. }
  1066. }
  1067. public bool IsSorted
  1068. {
  1069. get
  1070. {
  1071. return OrderBy.Length > 0;
  1072. }
  1073. }
  1074. public bool AllowRemove
  1075. {
  1076. get
  1077. {
  1078. return true;
  1079. }
  1080. }
  1081. public bool SupportsSearching
  1082. {
  1083. get
  1084. {
  1085. return false;
  1086. }
  1087. }
  1088. public ListSortDirection SortDirection
  1089. {
  1090. get
  1091. {
  1092. return (OrderBy.ToLower().IndexOf(" desc") > 0) ? ListSortDirection.Descending : ListSortDirection.Ascending;
  1093. }
  1094. }
  1095. public event ListChangedEventHandler ListChanged;
  1096. public bool SupportsChangeNotification
  1097. {
  1098. get
  1099. {
  1100. return true;
  1101. }
  1102. }
  1103. public void RemoveSort()
  1104. {
  1105. throw new NotSupportedException();
  1106. }
  1107. object IBindingList.AddNew()
  1108. {
  1109. return AddNew();
  1110. }
  1111. public bool AllowEdit
  1112. {
  1113. get
  1114. {
  1115. return true;
  1116. }
  1117. }
  1118. public void RemoveIndex(PropertyDescriptor property)
  1119. {
  1120. throw new NotSupportedException();
  1121. }
  1122. #endregion
  1123. #region IListSource Members
  1124. public IList GetList()
  1125. {
  1126. return this;
  1127. }
  1128. public bool ContainsListCollection
  1129. {
  1130. get
  1131. {
  1132. return false;
  1133. }
  1134. }
  1135. #endregion
  1136. #region PropertyDescriptor
  1137. private class CSFieldDescriptor : PropertyDescriptor
  1138. {
  1139. readonly Type _type;
  1140. readonly PropertyInfo _propertyInfo;
  1141. public CSFieldDescriptor(Type type, PropertyInfo propertyInfo)
  1142. : base(propertyInfo.Name, new Attribute[] { })
  1143. {
  1144. _type = type;
  1145. _propertyInfo = propertyInfo;
  1146. }
  1147. public override object GetValue(object component)
  1148. {
  1149. if (!component.GetType().IsSubclassOf(_type))
  1150. return null;
  1151. return _propertyInfo.GetValue(component, null);
  1152. }
  1153. public override void SetValue(object component, object value)
  1154. {
  1155. if (!component.GetType().IsSubclassOf(_type))
  1156. return;
  1157. _propertyInfo.SetValue(component, value, null);
  1158. }
  1159. public override void ResetValue(object component)
  1160. {
  1161. }
  1162. public override bool CanResetValue(object component)
  1163. {
  1164. return false;
  1165. }
  1166. public override Type PropertyType
  1167. {
  1168. get
  1169. {
  1170. return _propertyInfo.PropertyType;
  1171. }
  1172. }
  1173. public override Type ComponentType
  1174. {
  1175. get
  1176. {
  1177. return _type;
  1178. }
  1179. }
  1180. public override bool IsReadOnly
  1181. {
  1182. get
  1183. {
  1184. return !_propertyInfo.CanWrite;
  1185. }
  1186. }
  1187. public override bool ShouldSerializeValue(object component)
  1188. {
  1189. return false;
  1190. }
  1191. }
  1192. #endregion
  1193. #endif
  1194. public event EventHandler Disposed;
  1195. public void Dispose()
  1196. {
  1197. if (_objectArray != null)
  1198. _objectArray.Clear();
  1199. _objectArray = null;
  1200. if (Disposed != null)
  1201. Disposed(this, EventArgs.Empty);
  1202. }
  1203. void IList<TObjectType>.Insert(int index, TObjectType item)
  1204. {
  1205. thro

Large files files are truncated, but you can click here to view the full file