2 // System.Data.DataRelationCollection.cs
5 // Christopher Podurgiel (cpodurgiel@msn.com)
6 // Daniel Morgan <danmorg@sc.rr.com>
7 // Tim Coleman (tim@timcoleman.com)
8 // Alan Tam Siu Lung <Tam@SiuLung.com>
10 // (C) Chris Podurgiel
11 // (C) 2002 Daniel Morgan
12 // Copyright (C) Tim Coleman, 2002
16 using System.Collections;
17 using System.ComponentModel;
19 namespace System.Data {
21 /// Represents the collection of DataRelation objects for this DataSet.
24 [DefaultEvent ("CollectionChanged")]
26 public abstract class DataRelationCollection : InternalDataCollectionBase
29 /// Summary description for DataTableRelationCollection.
31 internal class DataSetRelationCollection : DataRelationCollection
33 private DataSet dataSet;
36 /// Initializes a new instance of the DataSetRelationCollection class.
38 internal DataSetRelationCollection (DataSet dataSet)
40 this.dataSet = dataSet;
44 /// Gets the DataRelation object specified by name.
46 public override DataRelation this [string name]
49 int index = IndexOf (name, true);
50 return index < 0 ? null : (DataRelation) list[index];
55 /// Gets the DataRelation object at the specified index.
57 public override DataRelation this [int index]
60 return List [index] as DataRelation;
64 protected override DataSet GetDataSet()
70 /// Performs verification on the table.
72 /// <param name="relation">The relation to check.</param>
73 protected override void AddCore (DataRelation relation)
75 base.AddCore (relation);
76 if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet)
77 throw new DataException ();
78 relation.SetDataSet (dataSet);
79 relation.ParentTable.ChildRelations.Add (relation);
80 relation.ChildTable.ParentRelations.Add (relation);
81 ForeignKeyConstraint foreignKeyConstraint = null;
83 if (relation.createConstraints)
86 UniqueConstraint uniqueConstraint = null;
87 ConstraintCollection parentConstrains = relation.ParentTable.Constraints;
88 // find if the unique constraint already exists in the parent table.
89 foreach (Constraint o in parentConstrains)
91 if (o is UniqueConstraint)
93 UniqueConstraint uc = (UniqueConstraint) o;
94 if (uc.Columns.Length == relation.ParentColumns.Length)
96 bool allColumnsEqual = true;
97 for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt)
99 if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt])
101 allColumnsEqual = false;
107 uniqueConstraint = uc;
113 // if we did not find the unique constraint in the parent table.
114 // we generate new uniqueconastraint and add it to the parent table.
115 if (uniqueConstraint == null)
117 uniqueConstraint = new UniqueConstraint(relation.ParentColumns, false);
118 relation.ParentTable.Constraints.Add(uniqueConstraint);
121 foreignKeyConstraint = new ForeignKeyConstraint (relation.RelationName, relation.ParentColumns, relation.ChildColumns);
122 relation.ChildTable.Constraints.Add (foreignKeyConstraint);
124 relation.SetParentKeyConstraint (uniqueConstraint);
125 relation.SetChildKeyConstraint (foreignKeyConstraint);
131 public override void AddRange (DataRelation[] relations)
133 base.AddRange (relations);
136 public override void Clear ()
138 for (int i = 0; i < Count; i++)
144 protected override void RemoveCore (DataRelation relation)
146 relation.SetDataSet (null);
147 relation.ParentTable.ChildRelations.Remove (relation);
148 relation.ChildTable.ParentRelations.Remove (relation);
149 relation.SetParentKeyConstraint (null);
150 relation.SetChildKeyConstraint (null);
153 protected override ArrayList List {
161 /// Summary description for DataTableRelationCollection.
163 internal class DataTableRelationCollection : DataRelationCollection
165 private DataTable dataTable;
168 /// Initializes a new instance of the DataTableRelationCollection class.
170 internal DataTableRelationCollection (DataTable dataTable)
172 this.dataTable = dataTable;
176 /// Gets the DataRelation object specified by name.
178 public override DataRelation this [string name]
181 int index = IndexOf (name, true);
182 return index < 0 ? null : (DataRelation) list[index];
187 /// Gets the DataRelation object at the specified index.
189 public override DataRelation this [int index]
192 return List [index] as DataRelation;
196 protected override DataSet GetDataSet()
198 return dataTable.DataSet;
201 protected override void AddCore (DataRelation relation)
203 base.AddCore (relation);
206 protected override void RemoveCore (DataRelation relation)
208 base.RemoveCore (relation);
211 protected override ArrayList List {
218 private int defaultNameIndex;
219 private bool inTransition;
224 /// Initializes a new instance of the DataRelationCollection class.
226 protected DataRelationCollection ()
229 defaultNameIndex = 1;
230 inTransition = false;
234 /// Gets the DataRelation object specified by name.
236 public abstract DataRelation this[string name]{get;}
239 /// Gets the DataRelation object at the specified index.
241 public abstract DataRelation this[int index]{get;}
245 private string GetNextDefaultRelationName ()
248 string defRelationName = "Relation" +index;
249 for (; Contains (defRelationName); ++index) {
250 defRelationName = "Relation" + index;
252 return defRelationName;
256 /// Adds a DataRelation to the DataRelationCollection.
258 /// <param name="relation">The DataRelation to add to the collection.</param>
260 public void Add(DataRelation relation)
262 this.AddCore (relation);
263 if(relation.RelationName == string.Empty)
264 relation.RelationName = GenerateRelationName();
265 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
266 //List.Add(relation);
267 OnCollectionChanged(e);
270 private string GenerateRelationName()
273 return "Relation" + index;
277 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
278 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
279 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
280 /// The CollectionChanged event is fired if it succeeds.
282 /// <param name="parentColumn">parent column of relation.</param>
283 /// <param name="childColumn">child column of relation.</param>
284 /// <returns>The created DataRelation.</returns>
285 public virtual DataRelation Add(DataColumn parentColumn, DataColumn childColumn)
287 DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumn, childColumn);
293 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
294 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
295 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
296 /// The CollectionChanged event is raised if it succeeds.
298 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
299 /// <param name="childColumns">An array of child DataColumn objects.</param>
300 /// <returns>The created DataRelation.</returns>
301 public virtual DataRelation Add(DataColumn[] parentColumns, DataColumn[] childColumns)
303 DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumns, childColumns);
309 /// Creates a relation given the parameters and adds it to the collection.
310 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
311 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
312 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
313 /// The CollectionChanged event is raised if it succeeds.
315 /// <param name="name">The name of the relation.</param>
316 /// <param name="parentColumn">parent column of relation.</param>
317 /// <returns>The created DataRelation.</returns>
318 /// <returns></returns>
319 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn)
321 //If no name was supplied, give it a default name.
322 if (name == null || name == "") name = GetNextDefaultRelationName ();
324 DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn);
330 /// Creates a DataRelation with the specified name, and arrays of parent and child columns, and adds it to the collection.
332 /// <param name="name">The name of the DataRelation to create.</param>
333 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
334 /// <param name="childColumns">An array of child DataColumn objects.</param>
335 /// <returns>The created DataRelation.</returns>
336 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns)
338 //If no name was supplied, give it a default name.
339 if (name == null || name == "") name = GetNextDefaultRelationName ();
341 DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns);
347 /// Creates a relation given the parameters and adds it to the collection.
348 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
349 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
350 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
351 /// The CollectionChanged event is raised if it succeeds.
353 /// <param name="name">The name of the relation.</param>
354 /// <param name="parentColumn">parent column of relation.</param>
355 /// <param name="childColumn">child column of relation.</param>
356 /// <param name="createConstraints">true to create constraints; otherwise false. (default is true)</param>
357 /// <returns>The created DataRelation.</returns>
358 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn, bool createConstraints)
360 //If no name was supplied, give it a default name.
361 if (name == null || name == "") name = GetNextDefaultRelationName ();
363 DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn, createConstraints);
369 /// Creates a DataRelation with the specified name, arrays of parent and child columns,
370 /// and value specifying whether to create a constraint, and adds it to the collection.
372 /// <param name="name">The name of the DataRelation to create.</param>
373 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
374 /// <param name="childColumns">An array of child DataColumn objects.</param>
375 /// <param name="createConstraints">true to create a constraint; otherwise false.</param>
376 /// <returns>The created DataRelation.</returns>
377 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints)
379 //If no name was supplied, give it a default name.
380 if (name == null || name == "") name = GetNextDefaultRelationName ();
382 DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns, createConstraints);
389 /// Performs verification on the table.
391 /// <param name="relation">The relation to check.</param>
393 protected virtual void AddCore(DataRelation relation)
395 if (relation == null)
397 //TODO: Issue a good exception message.
398 throw new ArgumentNullException();
400 if(List.IndexOf(relation) != -1)
402 //TODO: Issue a good exception message.
403 throw new ArgumentException();
406 // check if the collection has a relation with the same name.
407 int tmp = IndexOf(relation.RelationName);
408 // if we found a relation with same name we have to check
409 // that it is the same case.
410 // indexof can return a table with different case letters.
413 if(relation.RelationName == this[tmp].RelationName)
414 throw new DuplicateNameException("A DataRelation named '" + relation.RelationName + "' already belongs to this DataSet.");
420 /// Copies the elements of the specified DataRelation array to the end of the collection.
422 /// <param name="relations">The array of DataRelation objects to add to the collection.</param>
423 public virtual void AddRange(DataRelation[] relations)
425 foreach (DataRelation relation in relations) Add(relation);
428 public virtual bool CanRemove(DataRelation relation)
430 if (relation == null || !GetDataSet().Equals(relation.DataSet))
435 public virtual void Clear()
440 public virtual bool Contains(string name)
442 return (-1 != IndexOf (name, false));
445 private CollectionChangeEventArgs CreateCollectionChangeEvent (CollectionChangeAction action)
447 return new CollectionChangeEventArgs (action, this);
450 protected abstract DataSet GetDataSet();
452 public virtual int IndexOf(DataRelation relation)
454 return List.IndexOf(relation);
457 public virtual int IndexOf(string relationName)
459 return IndexOf(relationName, false);
462 private int IndexOf (string name, bool error)
464 int count = 0, match = -1;
465 for (int i = 0; i < list.Count; i++)
467 String name2 = ((DataRelation) list[i]).RelationName;
468 if (String.Compare (name, name2, true) == 0)
470 if (String.Compare (name, name2, false) == 0)
478 if (count > 1 && error)
479 throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
483 protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
485 if (CollectionChanged != null)
486 CollectionChanged (this, ccevent);
490 protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs ccevent)
492 throw new NotImplementedException ();
495 public void Remove (DataRelation relation)
497 RemoveCore (relation);
498 List.Remove (relation);
499 string name = "Relation" + index;
500 if (relation.RelationName == name)
502 OnCollectionChanged (CreateCollectionChangeEvent (CollectionChangeAction.Remove));
505 public void Remove (string name)
507 Remove ((DataRelation) List[IndexOf (name)]);
510 public void RemoveAt (int index)
516 protected virtual void RemoveCore(DataRelation relation)
518 // TODO: What have to be done?
521 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]
522 public event CollectionChangeEventHandler CollectionChanged;