DataTableCollection.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DataTableCollection.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. // <owner current="false" primary="false">[....]</owner>
  8. //------------------------------------------------------------------------------
  9. namespace System.Data {
  10. using System;
  11. using System.Diagnostics;
  12. using System.Collections;
  13. using System.ComponentModel;
  14. using System.Globalization;
  15. /// <devdoc>
  16. /// <para>
  17. /// Represents the collection of tables for the <see cref='System.Data.DataSet'/>.
  18. /// </para>
  19. /// </devdoc>
  20. [
  21. DefaultEvent("CollectionChanged"),
  22. Editor("Microsoft.VSDesigner.Data.Design.TablesCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
  23. ListBindable(false),
  24. ]
  25. public sealed class DataTableCollection : InternalDataCollectionBase {
  26. private readonly DataSet dataSet = null;
  27. // private DataTable[] tables = new DataTable[2];
  28. // private int tableCount = 0;
  29. private readonly ArrayList _list = new ArrayList();
  30. private int defaultNameIndex = 1;
  31. private DataTable[] delayedAddRangeTables = null;
  32. private CollectionChangeEventHandler onCollectionChangedDelegate = null;
  33. private CollectionChangeEventHandler onCollectionChangingDelegate = null;
  34. private static int _objectTypeCount; // Bid counter
  35. private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
  36. /// <devdoc>
  37. /// DataTableCollection constructor. Used only by DataSet.
  38. /// </devdoc>
  39. internal DataTableCollection(DataSet dataSet) {
  40. Bid.Trace("<ds.DataTableCollection.DataTableCollection|INFO> %d#, dataSet=%d\n", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0);
  41. this.dataSet = dataSet;
  42. }
  43. /// <devdoc>
  44. /// <para>
  45. /// Gets the tables
  46. /// in the collection as an object.
  47. /// </para>
  48. /// </devdoc>
  49. protected override ArrayList List {
  50. get {
  51. return _list;
  52. }
  53. }
  54. internal int ObjectID {
  55. get {
  56. return _objectID;
  57. }
  58. }
  59. /// <devdoc>
  60. /// <para>Gets the table specified by its index.</para>
  61. /// </devdoc>
  62. public DataTable this[int index] {
  63. get {
  64. try { // Perf: use the readonly _list field directly and let ArrayList check the range
  65. return(DataTable) _list[index];
  66. }
  67. catch(ArgumentOutOfRangeException) {
  68. throw ExceptionBuilder.TableOutOfRange(index);
  69. }
  70. }
  71. }
  72. /// <devdoc>
  73. /// <para>Gets the table in the collection with the given name (not case-sensitive).</para>
  74. /// </devdoc>
  75. public DataTable this[string name] {
  76. get {
  77. int index = InternalIndexOf(name);
  78. if (index == -2) {
  79. throw ExceptionBuilder.CaseInsensitiveNameConflict(name);
  80. }
  81. if (index == -3) {
  82. throw ExceptionBuilder.NamespaceNameConflict(name);
  83. }
  84. return (index < 0) ? null : (DataTable)_list[index];
  85. }
  86. }
  87. public DataTable this[string name, string tableNamespace] {
  88. get {
  89. if (tableNamespace == null)
  90. throw ExceptionBuilder.ArgumentNull("tableNamespace");
  91. int index = InternalIndexOf(name, tableNamespace);
  92. if (index == -2) {
  93. throw ExceptionBuilder.CaseInsensitiveNameConflict(name);
  94. }
  95. return (index < 0) ? null : (DataTable)_list[index];
  96. }
  97. }
  98. // Case-sensitive search in Schema, data and diffgram loading
  99. internal DataTable GetTable(string name, string ns)
  100. {
  101. for (int i = 0; i < _list.Count; i++) {
  102. DataTable table = (DataTable) _list[i];
  103. if (table.TableName == name && table.Namespace == ns)
  104. return table;
  105. }
  106. return null;
  107. }
  108. // Case-sensitive smart search: it will look for a table using the ns only if required to
  109. // resolve a conflict
  110. internal DataTable GetTableSmart(string name, string ns){
  111. int fCount = 0;
  112. DataTable fTable = null;
  113. for (int i = 0; i < _list.Count; i++) {
  114. DataTable table = (DataTable) _list[i];
  115. if (table.TableName == name) {
  116. if (table.Namespace == ns)
  117. return table;
  118. fCount++;
  119. fTable = table;
  120. }
  121. }
  122. // if we get here we didn't match the namespace
  123. // so return the table only if fCount==1 (it's the only one)
  124. return (fCount == 1) ? fTable : null;
  125. }
  126. /// <devdoc>
  127. /// <para>
  128. /// Adds
  129. /// the specified table to the collection.
  130. /// </para>
  131. /// </devdoc>
  132. public void Add(DataTable table) {
  133. IntPtr hscp;
  134. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.Add|API> %d#, table=%d\n", ObjectID, (table!= null) ? table.ObjectID : 0);
  135. try {
  136. OnCollectionChanging(new CollectionChangeEventArgs(CollectionChangeAction.Add, table));
  137. BaseAdd(table);
  138. ArrayAdd(table);
  139. if (table.SetLocaleValue(dataSet.Locale, false, false) ||
  140. table.SetCaseSensitiveValue(dataSet.CaseSensitive, false, false)) {
  141. table.ResetIndexes();
  142. }
  143. OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, table));
  144. }
  145. finally {
  146. Bid.ScopeLeave(ref hscp);
  147. }
  148. }
  149. /// <devdoc>
  150. /// <para>[To be supplied.]</para>
  151. /// </devdoc>
  152. public void AddRange(DataTable[] tables) {
  153. IntPtr hscp;
  154. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.AddRange|API> %d#\n", ObjectID);
  155. try {
  156. if (dataSet.fInitInProgress) {
  157. delayedAddRangeTables = tables;
  158. return;
  159. }
  160. if (tables != null) {
  161. foreach(DataTable table in tables) {
  162. if (table != null) {
  163. Add(table);
  164. }
  165. }
  166. }
  167. }
  168. finally{
  169. Bid.ScopeLeave(ref hscp);
  170. }
  171. }
  172. /// <devdoc>
  173. /// <para>
  174. /// Creates a table with the given name and adds it to the
  175. /// collection.
  176. /// </para>
  177. /// </devdoc>
  178. public DataTable Add(string name) {
  179. DataTable table = new DataTable(name);
  180. // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet
  181. Add(table);
  182. return table;
  183. }
  184. public DataTable Add(string name, string tableNamespace) {
  185. DataTable table = new DataTable(name, tableNamespace);
  186. // fxcop: new DataTable should inherit the CaseSensitive, Locale from DataSet
  187. Add(table);
  188. return table;
  189. }
  190. /// <devdoc>
  191. /// <para>
  192. /// Creates a new table with a default name and adds it to
  193. /// the collection.
  194. /// </para>
  195. /// </devdoc>
  196. public DataTable Add() {
  197. DataTable table = new DataTable();
  198. // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet
  199. Add(table);
  200. return table;
  201. }
  202. /// <devdoc>
  203. /// <para>
  204. /// Occurs when the collection is changed.
  205. /// </para>
  206. /// </devdoc>
  207. [ResDescriptionAttribute(Res.collectionChangedEventDescr)]
  208. public event CollectionChangeEventHandler CollectionChanged {
  209. add {
  210. Bid.Trace("<ds.DataTableCollection.add_CollectionChanged|API> %d#\n", ObjectID);
  211. onCollectionChangedDelegate += value;
  212. }
  213. remove {
  214. Bid.Trace("<ds.DataTableCollection.remove_CollectionChanged|API> %d#\n", ObjectID);
  215. onCollectionChangedDelegate -= value;
  216. }
  217. }
  218. /// <devdoc>
  219. /// <para>[To be supplied.]</para>
  220. /// </devdoc>
  221. public event CollectionChangeEventHandler CollectionChanging {
  222. add {
  223. Bid.Trace("<ds.DataTableCollection.add_CollectionChanging|API> %d#\n", ObjectID);
  224. onCollectionChangingDelegate += value;
  225. }
  226. remove {
  227. Bid.Trace("<ds.DataTableCollection.remove_CollectionChanging|API> %d#\n", ObjectID);
  228. onCollectionChangingDelegate -= value;
  229. }
  230. }
  231. /// <devdoc>
  232. /// Adds the table to the tables array.
  233. /// </devdoc>
  234. private void ArrayAdd(DataTable table) {
  235. _list.Add(table);
  236. }
  237. /// <devdoc>
  238. /// Creates a new default name.
  239. /// </devdoc>
  240. internal string AssignName() {
  241. string newName = null;
  242. // RAIDBUG: 91671
  243. while(this.Contains( newName = MakeName(defaultNameIndex)))
  244. defaultNameIndex++;
  245. return newName;
  246. }
  247. /// <devdoc>
  248. /// Does verification on the table and it's name, and points the table at the dataSet that owns this collection.
  249. /// An ArgumentNullException is thrown if this table is null. An ArgumentException is thrown if this table
  250. /// already belongs to this collection, belongs to another collection.
  251. /// A DuplicateNameException is thrown if this collection already has a table with the same
  252. /// name (case insensitive).
  253. /// </devdoc>
  254. private void BaseAdd(DataTable table) {
  255. if (table == null)
  256. throw ExceptionBuilder.ArgumentNull("table");
  257. if (table.DataSet == dataSet)
  258. throw ExceptionBuilder.TableAlreadyInTheDataSet();
  259. if (table.DataSet != null)
  260. throw ExceptionBuilder.TableAlreadyInOtherDataSet();
  261. if (table.TableName.Length == 0)
  262. table.TableName = AssignName();
  263. else {
  264. if (NamesEqual(table.TableName, dataSet.DataSetName, false, dataSet.Locale) != 0 && !table.fNestedInDataset)
  265. throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName);
  266. RegisterName(table.TableName, table.Namespace);
  267. }
  268. table.SetDataSet(dataSet);
  269. //must run thru the document incorporating the addition of this data table
  270. //must make sure there is no other schema component which have the same
  271. // identity as this table (for example, there must not be a table with the
  272. // same identity as a column in this schema.
  273. }
  274. /// <devdoc>
  275. /// BaseGroupSwitch will intelligently remove and add tables from the collection.
  276. /// </devdoc>
  277. private void BaseGroupSwitch(DataTable[] oldArray, int oldLength, DataTable[] newArray, int newLength) {
  278. // We're doing a smart diff of oldArray and newArray to find out what
  279. // should be removed. We'll pass through oldArray and see if it exists
  280. // in newArray, and if not, do remove work. newBase is an opt. in case
  281. // the arrays have similar prefixes.
  282. int newBase = 0;
  283. for (int oldCur = 0; oldCur < oldLength; oldCur++) {
  284. bool found = false;
  285. for (int newCur = newBase; newCur < newLength; newCur++) {
  286. if (oldArray[oldCur] == newArray[newCur]) {
  287. if (newBase == newCur) {
  288. newBase++;
  289. }
  290. found = true;
  291. break;
  292. }
  293. }
  294. if (!found) {
  295. // This means it's in oldArray and not newArray. Remove it.
  296. if (oldArray[oldCur].DataSet == dataSet) {
  297. BaseRemove(oldArray[oldCur]);
  298. }
  299. }
  300. }
  301. // Now, let's pass through news and those that don't belong, add them.
  302. for (int newCur = 0; newCur < newLength; newCur++) {
  303. if (newArray[newCur].DataSet != dataSet) {
  304. BaseAdd(newArray[newCur]);
  305. _list.Add(newArray[newCur]);
  306. }
  307. }
  308. }
  309. /// <devdoc>
  310. /// Does verification on the table and it's name, and clears the table's dataSet pointer.
  311. /// An ArgumentNullException is thrown if this table is null. An ArgumentException is thrown
  312. /// if this table doesn't belong to this collection or if this table is part of a relationship.
  313. /// </devdoc>
  314. private void BaseRemove(DataTable table) {
  315. if (CanRemove(table, true)) {
  316. UnregisterName(table.TableName);
  317. table.SetDataSet(null);
  318. }
  319. _list.Remove(table);
  320. dataSet.OnRemovedTable(table);
  321. }
  322. /// <devdoc>
  323. /// <para>
  324. /// Verifies if a given table can be removed from the collection.
  325. /// </para>
  326. /// </devdoc>
  327. public bool CanRemove(DataTable table) {
  328. return CanRemove(table, false);
  329. }
  330. internal bool CanRemove(DataTable table, bool fThrowException) {
  331. IntPtr hscp;
  332. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.CanRemove|INFO> %d#, table=%d, fThrowException=%d{bool}\n", ObjectID, (table != null)? table.ObjectID : 0 , fThrowException);
  333. try {
  334. if (table == null) {
  335. if (!fThrowException)
  336. return false;
  337. else
  338. throw ExceptionBuilder.ArgumentNull("table");
  339. }
  340. if (table.DataSet != dataSet) {
  341. if (!fThrowException)
  342. return false;
  343. else
  344. throw ExceptionBuilder.TableNotInTheDataSet(table.TableName);
  345. }
  346. // allow subclasses to throw.
  347. dataSet.OnRemoveTable(table);
  348. if (table.ChildRelations.Count != 0 || table.ParentRelations.Count != 0) {
  349. if (!fThrowException)
  350. return false;
  351. else
  352. throw ExceptionBuilder.TableInRelation();
  353. }
  354. for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, table); constraints.GetNext();) {
  355. ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint();
  356. if (constraint.Table == table && constraint.RelatedTable == table) // we can go with (constraint.Table == constraint.RelatedTable)
  357. continue;
  358. if (!fThrowException)
  359. return false;
  360. else
  361. throw ExceptionBuilder.TableInConstraint(table, constraint);
  362. }
  363. for (ChildForeignKeyConstraintEnumerator constraints = new ChildForeignKeyConstraintEnumerator(dataSet, table); constraints.GetNext();) {
  364. ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint();
  365. if (constraint.Table == table && constraint.RelatedTable == table) // bug 97670
  366. continue;
  367. if (!fThrowException)
  368. return false;
  369. else
  370. throw ExceptionBuilder.TableInConstraint(table, constraint);
  371. }
  372. return true;
  373. }
  374. finally{
  375. Bid.ScopeLeave(ref hscp);
  376. }
  377. }
  378. /// <devdoc>
  379. /// <para>
  380. /// Clears the collection of any tables.
  381. /// </para>
  382. /// </devdoc>
  383. public void Clear() {
  384. IntPtr hscp;
  385. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.Clear|API> %d#\n", ObjectID);
  386. try {
  387. int oldLength = _list.Count;
  388. DataTable[] tables = new DataTable[_list.Count];
  389. _list.CopyTo(tables, 0);
  390. OnCollectionChanging(RefreshEventArgs);
  391. if (dataSet.fInitInProgress && delayedAddRangeTables != null) {
  392. delayedAddRangeTables = null;
  393. }
  394. BaseGroupSwitch(tables, oldLength, null, 0);
  395. _list.Clear();
  396. OnCollectionChanged(RefreshEventArgs);
  397. }
  398. finally {
  399. Bid.ScopeLeave(ref hscp);
  400. }
  401. }
  402. /// <devdoc>
  403. /// <para>
  404. /// Checks if a table, specified by name, exists in the collection.
  405. /// </para>
  406. /// </devdoc>
  407. public bool Contains(string name) {
  408. return (InternalIndexOf(name) >= 0);
  409. }
  410. public bool Contains(string name, string tableNamespace) {
  411. if (name == null)
  412. throw ExceptionBuilder.ArgumentNull("name");
  413. if (tableNamespace == null)
  414. throw ExceptionBuilder.ArgumentNull("tableNamespace");
  415. return (InternalIndexOf(name, tableNamespace) >= 0);
  416. }
  417. internal bool Contains(string name, string tableNamespace, bool checkProperty, bool caseSensitive) {
  418. if (!caseSensitive)
  419. return (InternalIndexOf(name) >= 0);
  420. // Case-Sensitive compare
  421. int count = _list.Count;
  422. for (int i = 0; i < count; i++) {
  423. DataTable table = (DataTable) _list[i];
  424. // this may be needed to check wether the cascading is creating some conflicts
  425. string ns = checkProperty ? table.Namespace : table.tableNamespace ;
  426. if (NamesEqual(table.TableName, name, true, dataSet.Locale) == 1 && (ns == tableNamespace))
  427. return true;
  428. }
  429. return false;
  430. }
  431. internal bool Contains(string name, bool caseSensitive) {
  432. if (!caseSensitive)
  433. return (InternalIndexOf(name) >= 0);
  434. // Case-Sensitive compare
  435. int count = _list.Count;
  436. for (int i = 0; i < count; i++) {
  437. DataTable table = (DataTable) _list[i];
  438. if (NamesEqual(table.TableName, name, true, dataSet.Locale) == 1 )
  439. return true;
  440. }
  441. return false;
  442. }
  443. public void CopyTo(DataTable[] array, int index) {
  444. if (array==null)
  445. throw ExceptionBuilder.ArgumentNull("array");
  446. if (index < 0)
  447. throw ExceptionBuilder.ArgumentOutOfRange("index");
  448. if (array.Length - index < _list.Count)
  449. throw ExceptionBuilder.InvalidOffsetLength();
  450. for(int i = 0; i < _list.Count; ++i) {
  451. array[index + i] = (DataTable)_list[i];
  452. }
  453. }
  454. /// <devdoc>
  455. /// <para>
  456. /// Returns the index of a specified <see cref='System.Data.DataTable'/>.
  457. /// </para>
  458. /// </devdoc>
  459. public int IndexOf(DataTable table) {
  460. int tableCount = _list.Count;
  461. for (int i = 0; i < tableCount; ++i) {
  462. if (table == (DataTable) _list[i]) {
  463. return i;
  464. }
  465. }
  466. return -1;
  467. }
  468. /// <devdoc>
  469. /// <para>
  470. /// Returns the index of the
  471. /// table with the given name (case insensitive), or -1 if the table
  472. /// doesn't exist in the collection.
  473. /// </para>
  474. /// </devdoc>
  475. public int IndexOf(string tableName) {
  476. int index = InternalIndexOf(tableName);
  477. return (index < 0) ? -1 : index;
  478. }
  479. public int IndexOf(string tableName, string tableNamespace) {
  480. return IndexOf( tableName, tableNamespace, true);
  481. }
  482. internal int IndexOf(string tableName, string tableNamespace, bool chekforNull) { // this should be public! why it is missing?
  483. if (chekforNull) {
  484. if (tableName == null)
  485. throw ExceptionBuilder.ArgumentNull("tableName");
  486. if (tableNamespace == null)
  487. throw ExceptionBuilder.ArgumentNull("tableNamespace");
  488. }
  489. int index = InternalIndexOf(tableName, tableNamespace);
  490. return (index < 0) ? -1 : index;
  491. }
  492. internal void ReplaceFromInference(System.Collections.Generic.List<DataTable> tableList) {
  493. Debug.Assert(_list.Count == tableList.Count, "Both lists should have equal numbers of tables");
  494. _list.Clear();
  495. _list.AddRange(tableList);
  496. }
  497. // Return value:
  498. // >= 0: find the match
  499. // -1: No match
  500. // -2: At least two matches with different cases
  501. // -3: At least two matches with different namespaces
  502. internal int InternalIndexOf(string tableName) {
  503. int cachedI = -1;
  504. if ((null != tableName) && (0 < tableName.Length)) {
  505. int count = _list.Count;
  506. int result = 0;
  507. for (int i = 0; i < count; i++) {
  508. DataTable table = (DataTable) _list[i];
  509. result = NamesEqual(table.TableName, tableName, false, dataSet.Locale);
  510. if (result == 1) {
  511. // ok, we have found a table with the same name.
  512. // let's see if there are any others with the same name
  513. // if any let's return (-3) otherwise...
  514. for (int j=i+1;j<count;j++) {
  515. DataTable dupTable = (DataTable) _list[j];
  516. if (NamesEqual(dupTable.TableName, tableName, false, dataSet.Locale) == 1)
  517. return -3;
  518. }
  519. //... let's just return i
  520. return i;
  521. }
  522. if (result == -1)
  523. cachedI = (cachedI == -1) ? i : -2;
  524. }
  525. }
  526. return cachedI;
  527. }
  528. // Return value:
  529. // >= 0: find the match
  530. // -1: No match
  531. // -2: At least two matches with different cases
  532. internal int InternalIndexOf(string tableName, string tableNamespace) {
  533. int cachedI = -1;
  534. if ((null != tableName) && (0 < tableName.Length)) {
  535. int count = _list.Count;
  536. int result = 0;
  537. for (int i = 0; i < count; i++) {
  538. DataTable table = (DataTable) _list[i];
  539. result = NamesEqual(table.TableName, tableName, false, dataSet.Locale);
  540. if ((result == 1) && (table.Namespace == tableNamespace))
  541. return i;
  542. if ((result == -1) && (table.Namespace == tableNamespace))
  543. cachedI = (cachedI == -1) ? i : -2;
  544. }
  545. }
  546. return cachedI;
  547. }
  548. internal void FinishInitCollection() {
  549. if (delayedAddRangeTables != null) {
  550. foreach(DataTable table in delayedAddRangeTables) {
  551. if (table != null) {
  552. Add(table);
  553. }
  554. }
  555. delayedAddRangeTables = null;
  556. }
  557. }
  558. /// <devdoc>
  559. /// Makes a default name with the given index. e.g. Table1, Table2, ... Tablei
  560. /// </devdoc>
  561. private string MakeName(int index) {
  562. if (1 == index) {
  563. return "Table1";
  564. }
  565. return "Table" + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
  566. }
  567. /// <devdoc>
  568. /// <para>
  569. /// Raises the <see cref='System.Data.DataTableCollection.OnCollectionChanged'/> event.
  570. /// </para>
  571. /// </devdoc>
  572. private void OnCollectionChanged(CollectionChangeEventArgs ccevent) {
  573. if (onCollectionChangedDelegate != null) {
  574. Bid.Trace("<ds.DataTableCollection.OnCollectionChanged|INFO> %d#\n", ObjectID);
  575. onCollectionChangedDelegate(this, ccevent);
  576. }
  577. }
  578. /// <devdoc>
  579. /// <para>[To be supplied.]</para>
  580. /// </devdoc>
  581. private void OnCollectionChanging(CollectionChangeEventArgs ccevent) {
  582. if (onCollectionChangingDelegate != null) {
  583. Bid.Trace("<ds.DataTableCollection.OnCollectionChanging|INFO> %d#\n", ObjectID);
  584. onCollectionChangingDelegate(this, ccevent);
  585. }
  586. }
  587. /// <devdoc>
  588. /// Registers this name as being used in the collection. Will throw an ArgumentException
  589. /// if the name is already being used. Called by Add, All property, and Table.TableName property.
  590. /// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex.
  591. /// </devdoc>
  592. internal void RegisterName(string name, string tbNamespace) {
  593. Bid.Trace("<ds.DataTableCollection.RegisterName|INFO> %d#, name='%ls', tbNamespace='%ls'\n", ObjectID, name, tbNamespace);
  594. Debug.Assert (name != null);
  595. CultureInfo locale = dataSet.Locale;
  596. int tableCount = _list.Count;
  597. for (int i = 0; i < tableCount; i++) {
  598. DataTable table = (DataTable) _list[i];
  599. if (NamesEqual(name, table.TableName, true, locale) != 0 && (tbNamespace == table.Namespace)) {
  600. throw ExceptionBuilder.DuplicateTableName(((DataTable) _list[i]).TableName);
  601. }
  602. }
  603. if (NamesEqual(name, MakeName(defaultNameIndex), true, locale) != 0) {
  604. defaultNameIndex++;
  605. }
  606. }
  607. /// <devdoc>
  608. /// <para>
  609. /// Removes the specified table from the collection.
  610. /// </para>
  611. /// </devdoc>
  612. public void Remove(DataTable table) {
  613. IntPtr hscp;
  614. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.Remove|API> %d#, table=%d\n", ObjectID, (table != null) ? table.ObjectID : 0);
  615. try {
  616. OnCollectionChanging(new CollectionChangeEventArgs(CollectionChangeAction.Remove, table));
  617. BaseRemove(table);
  618. OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, table));
  619. }
  620. finally{
  621. Bid.ScopeLeave(ref hscp);
  622. }
  623. }
  624. /// <devdoc>
  625. /// <para>
  626. /// Removes the
  627. /// table at the given index from the collection
  628. /// </para>
  629. /// </devdoc>
  630. public void RemoveAt(int index) {
  631. IntPtr hscp;
  632. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.RemoveAt|API> %d#, index=%d\n", ObjectID, index);
  633. try {
  634. DataTable dt = this[index];
  635. if (dt == null)
  636. throw ExceptionBuilder.TableOutOfRange(index);
  637. Remove(dt);
  638. }
  639. finally {
  640. Bid.ScopeLeave(ref hscp);
  641. }
  642. }
  643. /// <devdoc>
  644. /// <para>
  645. /// Removes the table with a specified name from the
  646. /// collection.
  647. /// </para>
  648. /// </devdoc>
  649. public void Remove(string name) {
  650. IntPtr hscp;
  651. Bid.ScopeEnter(out hscp, "<ds.DataTableCollection.Remove|API> %d#, name='%ls'\n", ObjectID, name);
  652. try {
  653. DataTable dt = this[name];
  654. if (dt == null)
  655. throw ExceptionBuilder.TableNotInTheDataSet(name);
  656. Remove(dt);
  657. }
  658. finally{
  659. Bid.ScopeLeave(ref hscp);
  660. }
  661. }
  662. public void Remove(string name, string tableNamespace) {
  663. if (name == null)
  664. throw ExceptionBuilder.ArgumentNull("name");
  665. if (tableNamespace == null)
  666. throw ExceptionBuilder.ArgumentNull("tableNamespace");
  667. DataTable dt = this[name, tableNamespace];
  668. if (dt == null)
  669. throw ExceptionBuilder.TableNotInTheDataSet(name);
  670. Remove(dt);
  671. }
  672. /// <devdoc>
  673. /// Unregisters this name as no longer being used in the collection. Called by Remove, All property, and
  674. /// Table.TableName property. If the name is equivalent to the last proposed default name, we walk backwards
  675. /// to find the next proper default name to use.
  676. /// </devdoc>
  677. internal void UnregisterName(string name) {
  678. Bid.Trace("<ds.DataTableCollection.UnregisterName|INFO> %d#, name='%ls'\n", ObjectID, name);
  679. if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, dataSet.Locale) != 0) {
  680. do {
  681. defaultNameIndex--;
  682. } while (defaultNameIndex > 1 &&
  683. !Contains(MakeName(defaultNameIndex - 1)));
  684. }
  685. }
  686. }
  687. }