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]
61 return List [index] as DataRelation;
62 } catch (ArgumentOutOfRangeException e) {
63 throw new IndexOutOfRangeException (String.Format ("Cannot find relation {0}.", index));
68 protected override DataSet GetDataSet()
74 /// Performs verification on the table.
76 /// <param name="relation">The relation to check.</param>
77 protected override void AddCore (DataRelation relation)
79 base.AddCore (relation);
80 if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet)
81 throw new DataException ();
82 relation.SetDataSet (dataSet);
83 relation.ParentTable.ChildRelations.Add (relation);
84 relation.ChildTable.ParentRelations.Add (relation);
85 ForeignKeyConstraint foreignKeyConstraint = null;
87 if (relation.createConstraints)
90 UniqueConstraint uniqueConstraint = null;
91 ConstraintCollection parentConstrains = relation.ParentTable.Constraints;
92 // find if the unique constraint already exists in the parent table.
93 foreach (Constraint o in parentConstrains)
95 if (o is UniqueConstraint)
97 UniqueConstraint uc = (UniqueConstraint) o;
98 if (uc.Columns.Length == relation.ParentColumns.Length)
100 bool allColumnsEqual = true;
101 for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt)
103 if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt])
105 allColumnsEqual = false;
111 uniqueConstraint = uc;
117 // if we did not find the unique constraint in the parent table.
118 // we generate new uniqueconastraint and add it to the parent table.
119 if (uniqueConstraint == null)
121 uniqueConstraint = new UniqueConstraint(relation.ParentColumns, false);
122 relation.ParentTable.Constraints.Add(uniqueConstraint);
125 foreignKeyConstraint = new ForeignKeyConstraint (relation.RelationName, relation.ParentColumns, relation.ChildColumns);
126 relation.ChildTable.Constraints.Add (foreignKeyConstraint);
128 relation.SetParentKeyConstraint (uniqueConstraint);
129 relation.SetChildKeyConstraint (foreignKeyConstraint);
135 public override void AddRange (DataRelation[] relations)
137 base.AddRange (relations);
140 public override void Clear ()
142 for (int i = 0; i < Count; i++)
148 protected override void RemoveCore (DataRelation relation)
150 relation.SetDataSet (null);
151 relation.ParentTable.ChildRelations.Remove (relation);
152 relation.ChildTable.ParentRelations.Remove (relation);
153 relation.SetParentKeyConstraint (null);
154 relation.SetChildKeyConstraint (null);
157 protected override ArrayList List {
165 /// Summary description for DataTableRelationCollection.
167 internal class DataTableRelationCollection : DataRelationCollection
169 private DataTable dataTable;
172 /// Initializes a new instance of the DataTableRelationCollection class.
174 internal DataTableRelationCollection (DataTable dataTable)
176 this.dataTable = dataTable;
180 /// Gets the DataRelation object specified by name.
182 public override DataRelation this [string name]
185 int index = IndexOf (name, true);
186 return index < 0 ? null : (DataRelation) list[index];
191 /// Gets the DataRelation object at the specified index.
193 public override DataRelation this [int index]
197 return List [index] as DataRelation;
198 } catch (ArgumentOutOfRangeException e) {
199 throw new IndexOutOfRangeException (String.Format ("Cannot find relation {0}.", index));
204 protected override DataSet GetDataSet()
206 return dataTable.DataSet;
209 protected override void AddCore (DataRelation relation)
211 base.AddCore (relation);
214 protected override void RemoveCore (DataRelation relation)
216 base.RemoveCore (relation);
219 protected override ArrayList List {
226 private int defaultNameIndex;
227 private bool inTransition;
232 /// Initializes a new instance of the DataRelationCollection class.
234 protected DataRelationCollection ()
237 defaultNameIndex = 1;
238 inTransition = false;
242 /// Gets the DataRelation object specified by name.
244 public abstract DataRelation this[string name]{get;}
247 /// Gets the DataRelation object at the specified index.
249 public abstract DataRelation this[int index]{get;}
253 private string GetNextDefaultRelationName ()
256 string defRelationName = "Relation" +index;
257 for (; Contains (defRelationName); ++index) {
258 defRelationName = "Relation" + index;
260 return defRelationName;
264 /// Adds a DataRelation to the DataRelationCollection.
266 /// <param name="relation">The DataRelation to add to the collection.</param>
268 public void Add(DataRelation relation)
270 this.AddCore (relation);
271 if(relation.RelationName == string.Empty)
272 relation.RelationName = GenerateRelationName();
273 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
274 //List.Add(relation);
275 OnCollectionChanged(e);
278 private string GenerateRelationName()
281 return "Relation" + index;
285 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
286 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
287 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
288 /// The CollectionChanged event is fired if it succeeds.
290 /// <param name="parentColumn">parent column of relation.</param>
291 /// <param name="childColumn">child column of relation.</param>
292 /// <returns>The created DataRelation.</returns>
293 public virtual DataRelation Add(DataColumn parentColumn, DataColumn childColumn)
295 DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumn, childColumn);
301 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
302 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
303 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
304 /// The CollectionChanged event is raised if it succeeds.
306 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
307 /// <param name="childColumns">An array of child DataColumn objects.</param>
308 /// <returns>The created DataRelation.</returns>
309 public virtual DataRelation Add(DataColumn[] parentColumns, DataColumn[] childColumns)
311 DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumns, childColumns);
317 /// Creates a relation given the parameters and adds it to the collection.
318 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
319 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
320 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
321 /// The CollectionChanged event is raised if it succeeds.
323 /// <param name="name">The name of the relation.</param>
324 /// <param name="parentColumn">parent column of relation.</param>
325 /// <returns>The created DataRelation.</returns>
326 /// <returns></returns>
327 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn)
329 //If no name was supplied, give it a default name.
330 if (name == null || name == "") name = GetNextDefaultRelationName ();
332 DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn);
338 /// Creates a DataRelation with the specified name, and arrays of parent and child columns, and adds it to the collection.
340 /// <param name="name">The name of the DataRelation to create.</param>
341 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
342 /// <param name="childColumns">An array of child DataColumn objects.</param>
343 /// <returns>The created DataRelation.</returns>
344 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns)
346 //If no name was supplied, give it a default name.
347 if (name == null || name == "") name = GetNextDefaultRelationName ();
349 DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns);
355 /// Creates a relation given the parameters and adds it to the collection.
356 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
357 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
358 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
359 /// The CollectionChanged event is raised if it succeeds.
361 /// <param name="name">The name of the relation.</param>
362 /// <param name="parentColumn">parent column of relation.</param>
363 /// <param name="childColumn">child column of relation.</param>
364 /// <param name="createConstraints">true to create constraints; otherwise false. (default is true)</param>
365 /// <returns>The created DataRelation.</returns>
366 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn, bool createConstraints)
368 //If no name was supplied, give it a default name.
369 if (name == null || name == "") name = GetNextDefaultRelationName ();
371 DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn, createConstraints);
377 /// Creates a DataRelation with the specified name, arrays of parent and child columns,
378 /// and value specifying whether to create a constraint, and adds it to the collection.
380 /// <param name="name">The name of the DataRelation to create.</param>
381 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
382 /// <param name="childColumns">An array of child DataColumn objects.</param>
383 /// <param name="createConstraints">true to create a constraint; otherwise false.</param>
384 /// <returns>The created DataRelation.</returns>
385 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints)
387 //If no name was supplied, give it a default name.
388 if (name == null || name == "") name = GetNextDefaultRelationName ();
390 DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns, createConstraints);
397 /// Performs verification on the table.
399 /// <param name="relation">The relation to check.</param>
401 protected virtual void AddCore(DataRelation relation)
403 if (relation == null)
405 //TODO: Issue a good exception message.
406 throw new ArgumentNullException();
408 if(List.IndexOf(relation) != -1)
410 //TODO: Issue a good exception message.
411 throw new ArgumentException();
414 // check if the collection has a relation with the same name.
415 int tmp = IndexOf(relation.RelationName);
416 // if we found a relation with same name we have to check
417 // that it is the same case.
418 // indexof can return a table with different case letters.
421 if(relation.RelationName == this[tmp].RelationName)
422 throw new DuplicateNameException("A DataRelation named '" + relation.RelationName + "' already belongs to this DataSet.");
428 /// Copies the elements of the specified DataRelation array to the end of the collection.
430 /// <param name="relations">The array of DataRelation objects to add to the collection.</param>
431 public virtual void AddRange(DataRelation[] relations)
433 foreach (DataRelation relation in relations) Add(relation);
436 public virtual bool CanRemove(DataRelation relation)
438 if (relation == null || !GetDataSet().Equals(relation.DataSet))
443 public virtual void Clear()
448 public virtual bool Contains(string name)
450 return (-1 != IndexOf (name, false));
453 private CollectionChangeEventArgs CreateCollectionChangeEvent (CollectionChangeAction action)
455 return new CollectionChangeEventArgs (action, this);
458 protected abstract DataSet GetDataSet();
460 public virtual int IndexOf(DataRelation relation)
462 return List.IndexOf(relation);
465 public virtual int IndexOf(string relationName)
467 return IndexOf(relationName, false);
470 private int IndexOf (string name, bool error)
472 int count = 0, match = -1;
473 for (int i = 0; i < list.Count; i++)
475 String name2 = ((DataRelation) list[i]).RelationName;
476 if (String.Compare (name, name2, true) == 0)
478 if (String.Compare (name, name2, false) == 0)
486 if (count > 1 && error)
487 throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
491 protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
493 if (CollectionChanged != null)
494 CollectionChanged (this, ccevent);
498 protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs ccevent)
500 throw new NotImplementedException ();
503 public void Remove (DataRelation relation)
505 RemoveCore (relation);
506 List.Remove (relation);
507 string name = "Relation" + index;
508 if (relation.RelationName == name)
510 OnCollectionChanged (CreateCollectionChangeEvent (CollectionChangeAction.Remove));
513 public void Remove (string name)
515 Remove ((DataRelation) List[IndexOf (name)]);
518 public void RemoveAt (int index)
524 protected virtual void RemoveCore(DataRelation relation)
526 // TODO: What have to be done?
529 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]
530 public event CollectionChangeEventHandler CollectionChanged;