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