(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.Data / System.Data / DataRelationCollection.cs
blob45b15ee2d5780599dc02154b8ff64df184e305d9
1 //
2 // System.Data.DataRelationCollection.cs
3 //
4 // Author:
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>
9 //
10 // (C) Chris Podurgiel
11 // (C) 2002 Daniel Morgan
12 // Copyright (C) Tim Coleman, 2002
16 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
25 //
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
28 //
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System;
39 using System.Collections;
40 using System.ComponentModel;
42 namespace System.Data {
43 /// <summary>
44 /// Represents the collection of DataRelation objects for this DataSet.
45 /// </summary>
46 [Editor]
47 [DefaultEvent ("CollectionChanged")]
48 [DefaultProperty ("Table")]
49 [Serializable]
50 public abstract class DataRelationCollection : InternalDataCollectionBase
52 /// <summary>
53 /// Summary description for DataTableRelationCollection.
54 /// </summary>
55 internal class DataSetRelationCollection : DataRelationCollection
57 private DataSet dataSet;
59 /// <summary>
60 /// Initializes a new instance of the DataSetRelationCollection class.
61 /// </summary>
62 internal DataSetRelationCollection (DataSet dataSet)
64 this.dataSet = dataSet;
67 /// <summary>
68 /// Gets the DataRelation object specified by name.
69 /// </summary>
70 public override DataRelation this [string name]
72 get {
73 int index = IndexOf (name, true);
74 return index < 0 ? null : (DataRelation) List[index];
78 /// <summary>
79 /// Gets the DataRelation object at the specified index.
80 /// </summary>
81 public override DataRelation this [int index]
83 get {
84 try {
85 return List [index] as DataRelation;
86 } catch (ArgumentOutOfRangeException e) {
87 throw new IndexOutOfRangeException (String.Format ("Cannot find relation {0}.", index));
92 protected override DataSet GetDataSet()
94 return dataSet;
97 /// <summary>
98 /// Performs verification on the table.
99 /// </summary>
100 /// <param name="relation">The relation to check.</param>
101 protected override void AddCore (DataRelation relation)
103 base.AddCore (relation);
104 if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet)
105 throw new DataException ();
106 relation.SetDataSet (dataSet);
107 relation.ParentTable.ChildRelations.Add (relation);
108 relation.ChildTable.ParentRelations.Add (relation);
109 ForeignKeyConstraint foreignKeyConstraint = null;
111 if (relation.createConstraints)
114 UniqueConstraint uniqueConstraint = null;
115 ConstraintCollection parentConstrains = relation.ParentTable.Constraints;
116 // find if the unique constraint already exists in the parent table.
117 foreach (Constraint o in parentConstrains)
119 if (o is UniqueConstraint)
121 UniqueConstraint uc = (UniqueConstraint) o;
122 if (uc.Columns.Length == relation.ParentColumns.Length)
124 bool allColumnsEqual = true;
125 for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt)
127 if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt])
129 allColumnsEqual = false;
130 break;
133 if (allColumnsEqual)
135 uniqueConstraint = uc;
136 break;
141 // if we did not find the unique constraint in the parent table.
142 // we generate new uniqueconastraint and add it to the parent table.
143 if (uniqueConstraint == null)
145 uniqueConstraint = new UniqueConstraint(relation.ParentColumns, false);
146 relation.ParentTable.Constraints.Add(uniqueConstraint);
149 foreignKeyConstraint = new ForeignKeyConstraint (relation.RelationName, relation.ParentColumns, relation.ChildColumns);
150 relation.ChildTable.Constraints.Add (foreignKeyConstraint);
152 relation.SetParentKeyConstraint (uniqueConstraint);
153 relation.SetChildKeyConstraint (foreignKeyConstraint);
159 public override void AddRange (DataRelation[] relations)
161 base.AddRange (relations);
164 public override void Clear ()
166 for (int i = 0; i < Count; i++)
167 RemoveCore(this[i]);
169 base.Clear();
172 protected override void RemoveCore (DataRelation relation)
174 relation.SetDataSet (null);
175 relation.ParentTable.ChildRelations.Remove (relation);
176 relation.ChildTable.ParentRelations.Remove (relation);
177 relation.SetParentKeyConstraint (null);
178 relation.SetChildKeyConstraint (null);
181 protected override ArrayList List {
182 get {
183 return base.List;
188 /// <summary>
189 /// Summary description for DataTableRelationCollection.
190 /// </summary>
191 internal class DataTableRelationCollection : DataRelationCollection
193 private DataTable dataTable;
195 /// <summary>
196 /// Initializes a new instance of the DataTableRelationCollection class.
197 /// </summary>
198 internal DataTableRelationCollection (DataTable dataTable)
200 this.dataTable = dataTable;
203 /// <summary>
204 /// Gets the DataRelation object specified by name.
205 /// </summary>
206 public override DataRelation this [string name]
208 get {
209 int index = IndexOf (name, true);
210 return index < 0 ? null : (DataRelation) List[index];
214 /// <summary>
215 /// Gets the DataRelation object at the specified index.
216 /// </summary>
217 public override DataRelation this [int index]
219 get {
220 try {
221 return List [index] as DataRelation;
222 } catch (ArgumentOutOfRangeException e) {
223 throw new IndexOutOfRangeException (String.Format ("Cannot find relation {0}.", index));
228 protected override DataSet GetDataSet()
230 return dataTable.DataSet;
233 protected override void AddCore (DataRelation relation)
235 base.AddCore (relation);
238 protected override void RemoveCore (DataRelation relation)
240 base.RemoveCore (relation);
243 protected override ArrayList List {
244 get {
245 return base.List;
250 private int defaultNameIndex;
251 private bool inTransition;
252 int index;
255 /// <summary>
256 /// Initializes a new instance of the DataRelationCollection class.
257 /// </summary>
258 protected DataRelationCollection ()
259 : base ()
261 defaultNameIndex = 1;
262 inTransition = false;
265 /// <summary>
266 /// Gets the DataRelation object specified by name.
267 /// </summary>
268 public abstract DataRelation this[string name]{get;}
270 /// <summary>
271 /// Gets the DataRelation object at the specified index.
272 /// </summary>
273 public abstract DataRelation this[int index]{get;}
276 #region Add Methods
277 private string GetNextDefaultRelationName ()
279 int index = 1;
280 string defRelationName = "Relation" +index;
281 for (; Contains (defRelationName); ++index) {
282 defRelationName = "Relation" + index;
284 return defRelationName;
287 /// <summary>
288 /// Adds a DataRelation to the DataRelationCollection.
289 /// </summary>
290 /// <param name="relation">The DataRelation to add to the collection.</param>
291 [MonoTODO]
292 public void Add(DataRelation relation)
294 this.AddCore (relation);
295 if(relation.RelationName == string.Empty)
296 relation.RelationName = GenerateRelationName();
297 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
298 //List.Add(relation);
299 OnCollectionChanged(e);
302 private string GenerateRelationName()
304 index++;
305 return "Relation" + index;
308 /// <summary>
309 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
310 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
311 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
312 /// The CollectionChanged event is fired if it succeeds.
313 /// </summary>
314 /// <param name="parentColumn">parent column of relation.</param>
315 /// <param name="childColumn">child column of relation.</param>
316 /// <returns>The created DataRelation.</returns>
317 public virtual DataRelation Add(DataColumn parentColumn, DataColumn childColumn)
319 DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumn, childColumn);
320 Add(dataRelation);
321 return dataRelation;
324 /// <summary>
325 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
326 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
327 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
328 /// The CollectionChanged event is raised if it succeeds.
329 /// </summary>
330 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
331 /// <param name="childColumns">An array of child DataColumn objects.</param>
332 /// <returns>The created DataRelation.</returns>
333 public virtual DataRelation Add(DataColumn[] parentColumns, DataColumn[] childColumns)
335 DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumns, childColumns);
336 Add(dataRelation);
337 return dataRelation;
340 /// <summary>
341 /// Creates a relation given the parameters and adds it to the collection.
342 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
343 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
344 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
345 /// The CollectionChanged event is raised if it succeeds.
346 /// </summary>
347 /// <param name="name">The name of the relation.</param>
348 /// <param name="parentColumn">parent column of relation.</param>
349 /// <returns>The created DataRelation.</returns>
350 /// <returns></returns>
351 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn)
353 //If no name was supplied, give it a default name.
354 if (name == null || name == "") name = GetNextDefaultRelationName ();
356 DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn);
357 Add(dataRelation);
358 return dataRelation;
361 /// <summary>
362 /// Creates a DataRelation with the specified name, and arrays of parent and child columns, and adds it to the collection.
363 /// </summary>
364 /// <param name="name">The name of the DataRelation to create.</param>
365 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
366 /// <param name="childColumns">An array of child DataColumn objects.</param>
367 /// <returns>The created DataRelation.</returns>
368 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns)
370 //If no name was supplied, give it a default name.
371 if (name == null || name == "") name = GetNextDefaultRelationName ();
373 DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns);
374 Add(dataRelation);
375 return dataRelation;
378 /// <summary>
379 /// Creates a relation given the parameters and adds it to the collection.
380 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
381 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
382 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
383 /// The CollectionChanged event is raised if it succeeds.
384 /// </summary>
385 /// <param name="name">The name of the relation.</param>
386 /// <param name="parentColumn">parent column of relation.</param>
387 /// <param name="childColumn">child column of relation.</param>
388 /// <param name="createConstraints">true to create constraints; otherwise false. (default is true)</param>
389 /// <returns>The created DataRelation.</returns>
390 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn, bool createConstraints)
392 //If no name was supplied, give it a default name.
393 if (name == null || name == "") name = GetNextDefaultRelationName ();
395 DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn, createConstraints);
396 Add(dataRelation);
397 return dataRelation;
400 /// <summary>
401 /// Creates a DataRelation with the specified name, arrays of parent and child columns,
402 /// and value specifying whether to create a constraint, and adds it to the collection.
403 /// </summary>
404 /// <param name="name">The name of the DataRelation to create.</param>
405 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
406 /// <param name="childColumns">An array of child DataColumn objects.</param>
407 /// <param name="createConstraints">true to create a constraint; otherwise false.</param>
408 /// <returns>The created DataRelation.</returns>
409 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints)
411 //If no name was supplied, give it a default name.
412 if (name == null || name == "") name = GetNextDefaultRelationName ();
414 DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns, createConstraints);
415 Add(dataRelation);
416 return dataRelation;
418 #endregion
420 /// <summary>
421 /// Performs verification on the table.
422 /// </summary>
423 /// <param name="relation">The relation to check.</param>
424 [MonoTODO]
425 protected virtual void AddCore(DataRelation relation)
427 if (relation == null)
429 //TODO: Issue a good exception message.
430 throw new ArgumentNullException();
432 if(List.IndexOf(relation) != -1)
434 //TODO: Issue a good exception message.
435 throw new ArgumentException();
438 // check if the collection has a relation with the same name.
439 int tmp = IndexOf(relation.RelationName);
440 // if we found a relation with same name we have to check
441 // that it is the same case.
442 // indexof can return a table with different case letters.
443 if (tmp != -1)
445 if(relation.RelationName == this[tmp].RelationName)
446 throw new DuplicateNameException("A DataRelation named '" + relation.RelationName + "' already belongs to this DataSet.");
448 List.Add(relation);
451 /// <summary>
452 /// Copies the elements of the specified DataRelation array to the end of the collection.
453 /// </summary>
454 /// <param name="relations">The array of DataRelation objects to add to the collection.</param>
455 public virtual void AddRange(DataRelation[] relations)
457 foreach (DataRelation relation in relations) Add(relation);
460 public virtual bool CanRemove(DataRelation relation)
462 if (relation == null || !GetDataSet().Equals(relation.DataSet))
463 return false;
465 // check if the relation doesnot belong to this collection
466 int tmp = IndexOf(relation.RelationName);
467 // if we found a relation with same name we have to check
468 // that it is the same case.
469 // indexof can return a table with different case letters.
470 if (tmp != -1) {
471 if(relation.RelationName != this[tmp].RelationName)
472 return false;
474 else {
475 return false;
478 return true;
481 public virtual void Clear()
483 List.Clear();
486 public virtual bool Contains(string name)
488 return (-1 != IndexOf (name, false));
491 private CollectionChangeEventArgs CreateCollectionChangeEvent (CollectionChangeAction action)
493 return new CollectionChangeEventArgs (action, this);
496 protected abstract DataSet GetDataSet();
498 public virtual int IndexOf(DataRelation relation)
500 return List.IndexOf(relation);
503 public virtual int IndexOf(string relationName)
505 return IndexOf(relationName, false);
508 private int IndexOf (string name, bool error)
510 int count = 0, match = -1;
511 for (int i = 0; i < List.Count; i++)
513 String name2 = ((DataRelation) List[i]).RelationName;
514 if (String.Compare (name, name2, true) == 0)
516 if (String.Compare (name, name2, false) == 0)
517 return i;
518 match = i;
519 count++;
522 if (count == 1)
523 return match;
524 if (count > 1 && error)
525 throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
526 return -1;
529 protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
531 if (CollectionChanged != null)
532 CollectionChanged (this, ccevent);
535 [MonoTODO]
536 protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs ccevent)
538 throw new NotImplementedException ();
541 public void Remove (DataRelation relation)
543 if (relation == null)
544 throw new ArgumentNullException("Relation specified is null");
546 // check if the list doesnot contains this relation.
547 if (!(List.Contains(relation)))
548 throw new ArgumentException("Relation doesnot belong to this Collection.");
550 RemoveCore (relation);
551 List.Remove (relation);
552 string name = "Relation" + index;
553 if (relation.RelationName == name)
554 index--;
555 OnCollectionChanged (CreateCollectionChangeEvent (CollectionChangeAction.Remove));
558 public void Remove (string name)
560 Remove ((DataRelation) List[IndexOf (name)]);
563 public void RemoveAt (int index)
565 if (( index < 0 ) || (index >=List.Count))
566 throw new ArgumentException("There is no row at position "+index+".");
567 Remove(this[index]);
570 [MonoTODO]
571 protected virtual void RemoveCore(DataRelation relation)
573 // TODO: What have to be done?
576 #region Events
578 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]
579 public event CollectionChangeEventHandler CollectionChanged;
581 #endregion