ConstraintCollection.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. //------------------------------------------------------------------------------
  2. // <copyright file="ConstraintCollection.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. /// <devdoc>
  15. /// <para>Represents a collection of constraints for a <see cref='System.Data.DataTable'/>
  16. /// .</para>
  17. /// </devdoc>
  18. [
  19. DefaultEvent("CollectionChanged"),
  20. Editor("Microsoft.VSDesigner.Data.Design.ConstraintsCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
  21. ]
  22. public sealed class ConstraintCollection : InternalDataCollectionBase { // WebData 111752
  23. private readonly DataTable table;
  24. // private Constraint[] constraints = new Constraint[2];
  25. private readonly ArrayList list = new ArrayList();
  26. private int defaultNameIndex = 1;
  27. private CollectionChangeEventHandler onCollectionChanged;
  28. private Constraint[] delayLoadingConstraints;
  29. private bool fLoadForeignKeyConstraintsOnly = false;
  30. /// <devdoc>
  31. /// ConstraintCollection constructor. Used only by DataTable.
  32. /// </devdoc>
  33. internal ConstraintCollection(DataTable table) {
  34. this.table = table;
  35. }
  36. /// <devdoc>
  37. /// <para>Gets the list of objects contained by the collection.</para>
  38. /// </devdoc>
  39. protected override ArrayList List {
  40. get {
  41. return list;
  42. }
  43. }
  44. /// <devdoc>
  45. /// <para>Gets the <see cref='System.Data.Constraint'/>
  46. /// from the collection at the specified index.</para>
  47. /// </devdoc>
  48. public Constraint this[int index] {
  49. get {
  50. if (index >= 0 && index < List.Count) {
  51. return(Constraint) List[index];
  52. }
  53. throw ExceptionBuilder.ConstraintOutOfRange(index);
  54. }
  55. }
  56. /// <devdoc>
  57. /// The DataTable with which this ConstraintCollection is associated
  58. /// </devdoc>
  59. internal DataTable Table {
  60. get {
  61. return table;
  62. }
  63. }
  64. /// <devdoc>
  65. /// <para>Gets the <see cref='System.Data.Constraint'/> from the collection with the specified name.</para>
  66. /// </devdoc>
  67. public Constraint this[string name] {
  68. get {
  69. int index = InternalIndexOf(name);
  70. if (index == -2) {
  71. throw ExceptionBuilder.CaseInsensitiveNameConflict(name);
  72. }
  73. return (index < 0) ? null : (Constraint)List[index];
  74. }
  75. }
  76. /// <devdoc>
  77. /// <para>
  78. /// Adds the constraint to the collection.</para>
  79. /// </devdoc>
  80. public void Add(Constraint constraint) {
  81. Add(constraint, true);
  82. }
  83. // To add foreign key constraint without adding any unique constraint for internal use. Main purpose : Binary Remoting
  84. internal void Add(Constraint constraint, bool addUniqueWhenAddingForeign) {
  85. if (constraint == null)
  86. throw ExceptionBuilder.ArgumentNull("constraint");
  87. // It is an error if we find an equivalent constraint already in collection
  88. if (FindConstraint(constraint) != null) {
  89. throw ExceptionBuilder.DuplicateConstraint(FindConstraint(constraint).ConstraintName);
  90. }
  91. if (1 < table.NestedParentRelations.Length) {
  92. if (!AutoGenerated(constraint)) {
  93. throw ExceptionBuilder.CantAddConstraintToMultipleNestedTable(table.TableName);
  94. }
  95. }
  96. if (constraint is UniqueConstraint) {
  97. if (((UniqueConstraint)constraint).bPrimaryKey) {
  98. if (Table.primaryKey != null) {
  99. throw ExceptionBuilder.AddPrimaryKeyConstraint();
  100. }
  101. }
  102. AddUniqueConstraint((UniqueConstraint)constraint);
  103. }
  104. else if (constraint is ForeignKeyConstraint) {
  105. ForeignKeyConstraint fk = (ForeignKeyConstraint)constraint;
  106. if (addUniqueWhenAddingForeign) {
  107. UniqueConstraint key = fk.RelatedTable.Constraints.FindKeyConstraint(fk.RelatedColumnsReference);
  108. if (key == null) {
  109. if (constraint.ConstraintName.Length == 0)
  110. constraint.ConstraintName = AssignName();
  111. else
  112. RegisterName(constraint.ConstraintName);
  113. key = new UniqueConstraint(fk.RelatedColumnsReference);
  114. fk.RelatedTable.Constraints.Add(key);
  115. }
  116. }
  117. AddForeignKeyConstraint((ForeignKeyConstraint)constraint);
  118. }
  119. BaseAdd(constraint);
  120. ArrayAdd(constraint);
  121. OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, constraint));
  122. if (constraint is UniqueConstraint) {
  123. if (((UniqueConstraint)constraint).bPrimaryKey) {
  124. Table.PrimaryKey = ((UniqueConstraint)constraint).ColumnsReference;
  125. }
  126. }
  127. }
  128. /// <devdoc>
  129. /// <para>Constructs a new <see cref='System.Data.UniqueConstraint'/> using the
  130. /// specified array of <see cref='System.Data.DataColumn'/>
  131. /// objects and adds it to the collection.</para>
  132. /// </devdoc>
  133. public Constraint Add(string name, DataColumn[] columns, bool primaryKey) {
  134. UniqueConstraint constraint = new UniqueConstraint(name, columns);
  135. Add(constraint);
  136. if (primaryKey)
  137. Table.PrimaryKey = columns;
  138. return constraint;
  139. }
  140. /// <devdoc>
  141. /// <para>Constructs a new <see cref='System.Data.UniqueConstraint'/> using the
  142. /// specified <see cref='System.Data.DataColumn'/> and adds it to the collection.</para>
  143. /// </devdoc>
  144. public Constraint Add(string name, DataColumn column, bool primaryKey) {
  145. UniqueConstraint constraint = new UniqueConstraint(name, column);
  146. Add(constraint);
  147. if (primaryKey)
  148. Table.PrimaryKey = constraint.ColumnsReference;
  149. return constraint;
  150. }
  151. /// <devdoc>
  152. /// <para>
  153. /// Constructs a new <see cref='System.Data.ForeignKeyConstraint'/>
  154. /// with the
  155. /// specified parent and child
  156. /// columns and adds the constraint to the collection.</para>
  157. /// </devdoc>
  158. public Constraint Add(string name, DataColumn primaryKeyColumn, DataColumn foreignKeyColumn) {
  159. ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumn, foreignKeyColumn);
  160. Add(constraint);
  161. return constraint;
  162. }
  163. /// <devdoc>
  164. /// <para>Constructs a new <see cref='System.Data.ForeignKeyConstraint'/> with the specified parent columns and
  165. /// child columns and adds the constraint to the collection.</para>
  166. /// </devdoc>
  167. public Constraint Add(string name, DataColumn[] primaryKeyColumns, DataColumn[] foreignKeyColumns) {
  168. ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumns, foreignKeyColumns);
  169. Add(constraint);
  170. return constraint;
  171. }
  172. public void AddRange(Constraint[] constraints ) {
  173. if (table.fInitInProgress) {
  174. delayLoadingConstraints = constraints;
  175. fLoadForeignKeyConstraintsOnly = false;
  176. return;
  177. }
  178. if (constraints != null) {
  179. foreach(Constraint constr in constraints) {
  180. if (constr != null) {
  181. Add(constr);
  182. }
  183. }
  184. }
  185. }
  186. private void AddUniqueConstraint(UniqueConstraint constraint) {
  187. DataColumn[] columns = constraint.ColumnsReference;
  188. for (int i = 0; i < columns.Length; i++) {
  189. if (columns[i].Table != this.table) {
  190. throw ExceptionBuilder.ConstraintForeignTable();
  191. }
  192. }
  193. constraint.ConstraintIndexInitialize();
  194. if (!constraint.CanEnableConstraint()) {
  195. constraint.ConstraintIndexClear();
  196. throw ExceptionBuilder.UniqueConstraintViolation();
  197. }
  198. }
  199. private void AddForeignKeyConstraint(ForeignKeyConstraint constraint) {
  200. if (!constraint.CanEnableConstraint()) {
  201. throw ExceptionBuilder.ConstraintParentValues();
  202. }
  203. constraint.CheckCanAddToCollection(this);
  204. }
  205. private bool AutoGenerated(Constraint constraint) {
  206. ForeignKeyConstraint fk = (constraint as ForeignKeyConstraint);
  207. if (null != fk) {
  208. return XmlTreeGen.AutoGenerated(fk, false);
  209. }
  210. else {
  211. UniqueConstraint unique = (UniqueConstraint) constraint;
  212. return XmlTreeGen.AutoGenerated(unique);
  213. }
  214. }
  215. /// <devdoc>
  216. /// <para>Occurs when the <see cref='System.Data.ConstraintCollection'/> is changed through additions or
  217. /// removals.</para>
  218. /// </devdoc>
  219. public event CollectionChangeEventHandler CollectionChanged {
  220. add {
  221. onCollectionChanged += value;
  222. }
  223. remove {
  224. onCollectionChanged -= value;
  225. }
  226. }
  227. /// <devdoc>
  228. /// Adds the constraint to the constraints array.
  229. /// </devdoc>
  230. private void ArrayAdd(Constraint constraint) {
  231. Debug.Assert(constraint != null, "Attempt to add null constraint to constraint array");
  232. List.Add(constraint);
  233. }
  234. private void ArrayRemove(Constraint constraint) {
  235. List.Remove(constraint);
  236. }
  237. /// <devdoc>
  238. /// Creates a new default name.
  239. /// </devdoc>
  240. internal string AssignName() {
  241. string newName = MakeName(defaultNameIndex);
  242. defaultNameIndex++;
  243. return newName;
  244. }
  245. /// <devdoc>
  246. /// Does verification on the constraint and it's name.
  247. /// An ArgumentNullException is thrown if this constraint is null. An ArgumentException is thrown if this constraint
  248. /// already belongs to this collection, belongs to another collection.
  249. /// A DuplicateNameException is thrown if this collection already has a constraint with the same
  250. /// name (case insensitive).
  251. /// </devdoc>
  252. private void BaseAdd(Constraint constraint) {
  253. if (constraint == null)
  254. throw ExceptionBuilder.ArgumentNull("constraint");
  255. if (constraint.ConstraintName.Length == 0)
  256. constraint.ConstraintName = AssignName();
  257. else
  258. RegisterName(constraint.ConstraintName);
  259. constraint.InCollection = true;
  260. }
  261. /// <devdoc>
  262. /// BaseGroupSwitch will intelligently remove and add tables from the collection.
  263. /// </devdoc>
  264. private void BaseGroupSwitch(Constraint[] oldArray, int oldLength, Constraint[] newArray, int newLength) {
  265. // We're doing a smart diff of oldArray and newArray to find out what
  266. // should be removed. We'll pass through oldArray and see if it exists
  267. // in newArray, and if not, do remove work. newBase is an opt. in case
  268. // the arrays have similar prefixes.
  269. int newBase = 0;
  270. for (int oldCur = 0; oldCur < oldLength; oldCur++) {
  271. bool found = false;
  272. for (int newCur = newBase; newCur < newLength; newCur++) {
  273. if (oldArray[oldCur] == newArray[newCur]) {
  274. if (newBase == newCur) {
  275. newBase++;
  276. }
  277. found = true;
  278. break;
  279. }
  280. }
  281. if (!found) {
  282. // This means it's in oldArray and not newArray. Remove it.
  283. BaseRemove(oldArray[oldCur]);
  284. List.Remove(oldArray[oldCur]);
  285. }
  286. }
  287. // Now, let's pass through news and those that don't belong, add them.
  288. for (int newCur = 0; newCur < newLength; newCur++) {
  289. if (!newArray[newCur].InCollection)
  290. BaseAdd(newArray[newCur]);
  291. List.Add(newArray[newCur]);
  292. }
  293. }
  294. /// <devdoc>
  295. /// Does verification on the constraint and it's name.
  296. /// An ArgumentNullException is thrown if this constraint is null. An ArgumentException is thrown
  297. /// if this constraint doesn't belong to this collection or if this constraint is part of a relationship.
  298. /// </devdoc>
  299. private void BaseRemove(Constraint constraint) {
  300. if (constraint == null) {
  301. throw ExceptionBuilder.ArgumentNull("constraint");
  302. }
  303. if (constraint.Table != table) {
  304. throw ExceptionBuilder.ConstraintRemoveFailed();
  305. }
  306. UnregisterName(constraint.ConstraintName);
  307. constraint.InCollection = false;
  308. if (constraint is UniqueConstraint) {
  309. for (int i = 0; i < Table.ChildRelations.Count; i++) {
  310. DataRelation rel = Table.ChildRelations[i];
  311. if (rel.ParentKeyConstraint == constraint)
  312. rel.SetParentKeyConstraint(null);
  313. }
  314. ((UniqueConstraint)constraint).ConstraintIndexClear();
  315. }
  316. else if (constraint is ForeignKeyConstraint) {
  317. for (int i = 0; i < Table.ParentRelations.Count; i++) {
  318. DataRelation rel = Table.ParentRelations[i];
  319. if (rel.ChildKeyConstraint == constraint)
  320. rel.SetChildKeyConstraint(null);
  321. }
  322. }
  323. }
  324. /// <devdoc>
  325. /// <para>Indicates if a <see cref='System.Data.Constraint'/> can be removed.</para>
  326. /// </devdoc>
  327. // PUBLIC because called by design-time... need to consider this.
  328. public bool CanRemove(Constraint constraint) {
  329. return CanRemove(constraint, /*fThrowException:*/false);
  330. }
  331. internal bool CanRemove(Constraint constraint, bool fThrowException) {
  332. return constraint.CanBeRemovedFromCollection(this, fThrowException);
  333. }
  334. /// <devdoc>
  335. /// <para>Clears the collection of any <see cref='System.Data.Constraint'/>
  336. /// objects.</para>
  337. /// </devdoc>
  338. public void Clear() {
  339. if (table != null) {
  340. table.PrimaryKey = null;
  341. for (int i = 0; i < table.ParentRelations.Count; i++) {
  342. table.ParentRelations[i].SetChildKeyConstraint(null);
  343. }
  344. for (int i = 0; i < table.ChildRelations.Count; i++) {
  345. table.ChildRelations[i].SetParentKeyConstraint(null);
  346. }
  347. }
  348. if (table.fInitInProgress && delayLoadingConstraints != null) {
  349. delayLoadingConstraints = null;
  350. fLoadForeignKeyConstraintsOnly = false;
  351. }
  352. int oldLength = List.Count;
  353. Constraint[] constraints = new Constraint[List.Count];
  354. List.CopyTo(constraints, 0);
  355. try {
  356. // this will smartly add and remove the appropriate tables.
  357. BaseGroupSwitch(constraints, oldLength, null, 0);
  358. }
  359. catch (Exception e) {
  360. //
  361. if (Common.ADP.IsCatchableOrSecurityExceptionType(e)) {
  362. // something messed up. restore to original state.
  363. BaseGroupSwitch(null, 0, constraints, oldLength);
  364. List.Clear();
  365. for (int i = 0; i < oldLength; i++)
  366. List.Add(constraints[i]);
  367. }
  368. throw;
  369. }
  370. List.Clear();
  371. OnCollectionChanged(RefreshEventArgs);
  372. }
  373. /// <devdoc>
  374. /// <para>Indicates whether the <see cref='System.Data.Constraint'/>, specified by name, exists in the collection.</para>
  375. /// </devdoc>
  376. public bool Contains(string name) {
  377. return (InternalIndexOf(name) >= 0);
  378. }
  379. internal bool Contains(string name, bool caseSensitive) {
  380. if (!caseSensitive)
  381. return Contains(name);
  382. int index = InternalIndexOf(name);
  383. if (index<0)
  384. return false;
  385. return (name == ((Constraint) List[index]).ConstraintName);
  386. }
  387. public void CopyTo(Constraint[] array, int index) {
  388. if (array==null)
  389. throw ExceptionBuilder.ArgumentNull("array");
  390. if (index < 0)
  391. throw ExceptionBuilder.ArgumentOutOfRange("index");
  392. if (array.Length - index < list.Count)
  393. throw ExceptionBuilder.InvalidOffsetLength();
  394. for(int i = 0; i < list.Count; ++i) {
  395. array[index + i] = (Constraint)list[i];
  396. }
  397. }
  398. /// <devdoc>
  399. /// Returns a matching constriant object.
  400. /// </devdoc>
  401. internal Constraint FindConstraint(Constraint constraint) {
  402. int constraintCount = List.Count;
  403. for (int i = 0; i < constraintCount; i++) {
  404. if (((Constraint)List[i]).Equals(constraint))
  405. return(Constraint)List[i];
  406. }
  407. return null;
  408. }
  409. /// <devdoc>
  410. /// Returns a matching constriant object.
  411. /// </devdoc>
  412. internal UniqueConstraint FindKeyConstraint(DataColumn[] columns) {
  413. int constraintCount = List.Count;
  414. for (int i = 0; i < constraintCount; i++) {
  415. UniqueConstraint constraint = (List[i] as UniqueConstraint);
  416. if ((null != constraint) && CompareArrays(constraint.Key.ColumnsReference, columns)) {
  417. return constraint;
  418. }
  419. }
  420. return null;
  421. }
  422. /// <devdoc>
  423. /// Returns a matching constriant object.
  424. /// </devdoc>
  425. internal UniqueConstraint FindKeyConstraint(DataColumn column) {
  426. int constraintCount = List.Count;
  427. for (int i = 0; i < constraintCount; i++) {
  428. UniqueConstraint constraint = (List[i] as UniqueConstraint);
  429. if ((null != constraint) && (constraint.Key.ColumnsReference.Length == 1) && (constraint.Key.ColumnsReference[0] == column))
  430. return constraint;
  431. }
  432. return null;
  433. }
  434. /// <devdoc>
  435. /// Returns a matching constriant object.
  436. /// </devdoc>
  437. internal ForeignKeyConstraint FindForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) {
  438. int constraintCount = List.Count;
  439. for (int i = 0; i < constraintCount; i++) {
  440. ForeignKeyConstraint constraint = (List[i] as ForeignKeyConstraint);
  441. if ((null != constraint) &&
  442. CompareArrays(constraint.ParentKey.ColumnsReference, parentColumns) &&
  443. CompareArrays(constraint.ChildKey.ColumnsReference, childColumns))
  444. return constraint;
  445. }
  446. return null;
  447. }
  448. private static bool CompareArrays(DataColumn[] a1, DataColumn[] a2) {
  449. Debug.Assert(a1 != null && a2 != null, "Invalid Arguments");
  450. if (a1.Length != a2.Length)
  451. return false;
  452. int i, j;
  453. for (i=0; i<a1.Length; i++) {
  454. bool check = false;
  455. for (j=0; j<a2.Length; j++) {
  456. if (a1[i] ==a2[j]) {
  457. check = true;
  458. break;
  459. }
  460. }
  461. if (!check) {
  462. return false;
  463. }
  464. }
  465. return true;
  466. }
  467. /// <devdoc>
  468. /// <para>Returns the index of the specified <see cref='System.Data.Constraint'/> .</para>
  469. /// </devdoc>
  470. public int IndexOf(Constraint constraint) {
  471. if (null != constraint) {
  472. int count = Count;
  473. for (int i = 0; i < count; ++i) {
  474. if (constraint == (Constraint) List[i])
  475. return i;
  476. }
  477. // didnt find the constraint
  478. }
  479. return -1;
  480. }
  481. /// <devdoc>
  482. /// <para>Returns the index of the <see cref='System.Data.Constraint'/>, specified by name.</para>
  483. /// </devdoc>
  484. public int IndexOf(string constraintName) {
  485. int index = InternalIndexOf(constraintName);
  486. return (index < 0) ? -1 : index;
  487. }
  488. // Return value:
  489. // >= 0: find the match
  490. // -1: No match
  491. // -2: At least two matches with different cases
  492. internal int InternalIndexOf(string constraintName) {
  493. int cachedI = -1;
  494. if ((null != constraintName) && (0 < constraintName.Length)) {
  495. int constraintCount = List.Count;
  496. int result = 0;
  497. for (int i = 0; i < constraintCount; i++) {
  498. Constraint constraint = (Constraint) List[i];
  499. result = NamesEqual(constraint.ConstraintName, constraintName, false, table.Locale);
  500. if (result == 1)
  501. return i;
  502. if (result == -1)
  503. cachedI = (cachedI == -1) ? i : -2;
  504. }
  505. }
  506. return cachedI;
  507. }
  508. /// <devdoc>
  509. /// Makes a default name with the given index. e.g. Constraint1, Constraint2, ... Constrainti
  510. /// </devdoc>
  511. private string MakeName(int index) {
  512. if (1 == index) {
  513. return "Constraint1";
  514. }
  515. return "Constraint" + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
  516. }
  517. /// <devdoc>
  518. /// <para>Raises the <see cref='System.Data.ConstraintCollection.CollectionChanged'/> event.</para>
  519. /// </devdoc>
  520. private void OnCollectionChanged(CollectionChangeEventArgs ccevent) {
  521. if (onCollectionChanged != null) {
  522. onCollectionChanged(this, ccevent);
  523. }
  524. }
  525. /// <devdoc>
  526. /// Registers this name as being used in the collection. Will throw an ArgumentException
  527. /// if the name is already being used. Called by Add, All property, and Constraint.ConstraintName property.
  528. /// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex.
  529. /// </devdoc>
  530. internal void RegisterName(string name) {
  531. Debug.Assert (name != null);
  532. int constraintCount = List.Count;
  533. for (int i = 0; i < constraintCount; i++) {
  534. if (NamesEqual(name, ((Constraint)List[i]).ConstraintName, true, table.Locale) != 0) {
  535. throw ExceptionBuilder.DuplicateConstraintName(((Constraint)List[i]).ConstraintName);
  536. }
  537. }
  538. if (NamesEqual(name, MakeName(defaultNameIndex), true, table.Locale) != 0) {
  539. defaultNameIndex++;
  540. }
  541. }
  542. /// <devdoc>
  543. /// <para>
  544. /// Removes the specified <see cref='System.Data.Constraint'/>
  545. /// from the collection.</para>
  546. /// </devdoc>
  547. public void Remove(Constraint constraint) {
  548. if (constraint == null)
  549. throw ExceptionBuilder.ArgumentNull("constraint");
  550. // this will throw an exception if it can't be removed, otherwise indicates
  551. // whether we need to remove it from the collection.
  552. if (CanRemove(constraint, true)) {
  553. // constraint can be removed
  554. BaseRemove(constraint);
  555. ArrayRemove(constraint);
  556. if (constraint is UniqueConstraint && ((UniqueConstraint)constraint).IsPrimaryKey) {
  557. Table.PrimaryKey = null;
  558. }
  559. OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, constraint));
  560. }
  561. }
  562. /// <devdoc>
  563. /// <para>Removes the constraint at the specified index from the
  564. /// collection.</para>
  565. /// </devdoc>
  566. public void RemoveAt(int index) {
  567. Constraint c = this[index];
  568. if (c == null)
  569. throw ExceptionBuilder.ConstraintOutOfRange(index);
  570. Remove(c);
  571. }
  572. /// <devdoc>
  573. /// <para>Removes the constraint, specified by name, from the collection.</para>
  574. /// </devdoc>
  575. public void Remove(string name) {
  576. Constraint c = this[name];
  577. if (c == null)
  578. throw ExceptionBuilder.ConstraintNotInTheTable(name);
  579. Remove(c);
  580. }
  581. /// <devdoc>
  582. /// Unregisters this name as no longer being used in the collection. Called by Remove, All property, and
  583. /// Constraint.ConstraintName property. If the name is equivalent to the last proposed default name, we walk backwards
  584. /// to find the next proper default name to use.
  585. /// </devdoc>
  586. internal void UnregisterName(string name) {
  587. if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, table.Locale) != 0) {
  588. do {
  589. defaultNameIndex--;
  590. } while (defaultNameIndex > 1 &&
  591. !Contains(MakeName(defaultNameIndex - 1)));
  592. }
  593. }
  594. internal void FinishInitConstraints() {
  595. if (delayLoadingConstraints == null)
  596. return;
  597. int colCount;
  598. DataColumn[] parents, childs;
  599. for (int i = 0; i < delayLoadingConstraints.Length; i++) {
  600. if (delayLoadingConstraints[i] is UniqueConstraint) {
  601. if (fLoadForeignKeyConstraintsOnly)
  602. continue;
  603. UniqueConstraint constr = (UniqueConstraint) delayLoadingConstraints[i];
  604. if (constr.columnNames == null) {
  605. this.Add(constr);
  606. continue;
  607. }
  608. colCount = constr.columnNames.Length;
  609. parents = new DataColumn[colCount];
  610. for (int j = 0; j < colCount; j++)
  611. parents[j] = table.Columns[constr.columnNames[j]];
  612. if (constr.bPrimaryKey) {
  613. if (table.primaryKey != null) {
  614. throw ExceptionBuilder.AddPrimaryKeyConstraint();
  615. }
  616. else {
  617. Add(constr.ConstraintName,parents,true);
  618. }
  619. continue;
  620. }
  621. UniqueConstraint newConstraint = new UniqueConstraint(constr.constraintName, parents);
  622. if (FindConstraint(newConstraint) == null)
  623. this.Add(newConstraint);
  624. }
  625. else {
  626. ForeignKeyConstraint constr = (ForeignKeyConstraint) delayLoadingConstraints[i];
  627. if (constr.parentColumnNames == null ||constr.childColumnNames == null) {
  628. this.Add(constr);
  629. continue;
  630. }
  631. if (table.DataSet == null) {
  632. fLoadForeignKeyConstraintsOnly = true;
  633. continue;
  634. }
  635. colCount = constr.parentColumnNames.Length;
  636. parents = new DataColumn[colCount];
  637. childs = new DataColumn[colCount];
  638. for (int j = 0; j < colCount; j++) {
  639. if (constr.parentTableNamespace == null)
  640. parents[j] = table.DataSet.Tables[constr.parentTableName].Columns[constr.parentColumnNames[j]];
  641. else
  642. parents[j] = table.DataSet.Tables[constr.parentTableName, constr.parentTableNamespace].Columns[constr.parentColumnNames[j]];
  643. childs[j] = table.Columns[constr.childColumnNames[j]];
  644. }
  645. ForeignKeyConstraint newConstraint = new ForeignKeyConstraint(constr.constraintName, parents, childs);
  646. newConstraint.AcceptRejectRule = constr.acceptRejectRule;
  647. newConstraint.DeleteRule = constr.deleteRule;
  648. newConstraint.UpdateRule = constr.updateRule;
  649. this.Add(newConstraint);
  650. }
  651. }
  652. if (!fLoadForeignKeyConstraintsOnly)
  653. delayLoadingConstraints = null;
  654. }
  655. }
  656. }