Fixed the build
[mono.git] / mcs / class / System.Data / System.Data / DataRelationCollection.cs
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
13 //
14
15 using System;
16 using System.Collections;
17 using System.ComponentModel;
18
19 namespace System.Data {
20         /// <summary>
21         /// Represents the collection of DataRelation objects for this DataSet.
22         /// </summary>
23         [Editor]
24         [DefaultEvent ("CollectionChanged")]
25         [Serializable]
26         public abstract class DataRelationCollection : InternalDataCollectionBase
27         {
28                 /// <summary>
29                 /// Summary description for DataTableRelationCollection.
30                 /// </summary>
31                 internal class DataSetRelationCollection : DataRelationCollection
32                 {
33                         private DataSet dataSet;
34                         
35                         /// <summary>
36                         /// Initializes a new instance of the DataSetRelationCollection class.
37                         /// </summary>
38                         internal DataSetRelationCollection (DataSet dataSet)
39                         {
40                                 this.dataSet = dataSet;
41                         }
42
43                         /// <summary>
44                         /// Gets the DataRelation object specified by name.
45                         /// </summary>
46                         public override DataRelation this [string name]
47                         {
48                                 get {
49                                         foreach (DataRelation dataRelation in List)
50                                                 if (dataRelation.RelationName == name) return dataRelation;
51                                         return null;
52                                 }
53                         }
54
55                         /// <summary>
56                         /// Gets the DataRelation object at the specified index.
57                         /// </summary>
58                         public override DataRelation this [int index]
59                         {
60                                 get {
61                                         return List [index] as DataRelation;
62                                 }
63                         }
64
65                         protected override DataSet GetDataSet()
66                         {
67                                 return dataSet;
68                         }
69
70                         /// <summary>
71                         /// Performs verification on the table.
72                         /// </summary>
73                         /// <param name="relation">The relation to check.</param>
74                         protected override void AddCore (DataRelation relation)
75                         {
76                                 base.AddCore (relation);
77                                 if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet)
78                                         throw new DataException ();
79                                 List.Add (relation);
80                                 relation.SetDataSet (dataSet);
81                                 relation.ParentTable.ChildRelations.Add (relation);
82                                 relation.ChildTable.ParentRelations.Add (relation);
83                                 ForeignKeyConstraint foreignKeyConstraint = null;
84                                 if (relation.createConstraints) {
85                                         foreignKeyConstraint = new ForeignKeyConstraint (relation.ParentColumns, relation.ChildColumns);
86                                         relation.ChildTable.Constraints.Add (foreignKeyConstraint);
87                                 }
88                                 UniqueConstraint uniqueConstraint = null;
89                                 foreach (object o in List) {
90                                         if (o is UniqueConstraint) {
91                                                 UniqueConstraint uc = (UniqueConstraint) o;
92                                                 if (uc.Columns.Length == relation.ParentColumns.Length) {
93                                                         bool allColumnsEqual = true;
94                                                         for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt) {
95                                                                 if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt]) {
96                                                                         allColumnsEqual = false;
97                                                                         break;
98                                                                 }
99                                                         }
100                                                         if (allColumnsEqual) {
101                                                                 uniqueConstraint = uc;
102                                                                 break;
103                                                         }
104                                                 }
105                                         }
106                                 }
107                                 relation.SetParentKeyConstraint (uniqueConstraint);
108                                 relation.SetChildKeyConstraint (foreignKeyConstraint);
109                         }
110
111                         public override void AddRange (DataRelation[] relations)
112                         {
113                                 base.AddRange (relations);
114                         }
115
116                         public override void Clear ()
117                         {
118                                 base.Clear ();
119                         }
120
121                         protected override void RemoveCore (DataRelation relation)
122                         {
123                                 base.RemoveCore (relation);
124                                 relation.SetDataSet (null);
125                                 relation.ParentTable.ChildRelations.Remove (relation);
126                                 relation.ChildTable.ParentRelations.Remove (relation);
127                                 ForeignKeyConstraint foreignKeyConstraint = null;
128                                 relation.SetParentKeyConstraint (null);
129                                 relation.SetChildKeyConstraint (null);
130                         }
131
132                         protected override ArrayList List {
133                                 get {
134                                         return base.List;
135                                 }
136                         }
137                 }
138
139                 /// <summary>
140                 /// Summary description for DataTableRelationCollection.
141                 /// </summary>
142                 internal class DataTableRelationCollection : DataRelationCollection
143                 {
144                         private DataTable dataTable;
145                         
146                         /// <summary>
147                         /// Initializes a new instance of the DataTableRelationCollection class.
148                         /// </summary>
149                         internal DataTableRelationCollection (DataTable dataTable)
150                         {
151                                 this.dataTable = dataTable;
152                         }
153
154                         /// <summary>
155                         /// Gets the DataRelation object specified by name.
156                         /// </summary>
157                         public override DataRelation this [string name]
158                         {
159                                 get {
160                                         foreach (DataRelation dataRelation in List)
161                                                 if (dataRelation.RelationName == name) return dataRelation;
162                                         return null;
163                                 }
164                         }
165
166                         /// <summary>
167                         /// Gets the DataRelation object at the specified index.
168                         /// </summary>
169                         public override DataRelation this [int index]
170                         {
171                                 get {
172                                         return List [index] as DataRelation;
173                                 }
174                         }
175
176                         protected override DataSet GetDataSet()
177                         {
178                                 return dataTable.DataSet;
179                         }
180
181                         protected override void AddCore (DataRelation relation)
182                         {
183                                 base.AddCore (relation);
184                                 GetDataSet ().Relations.Add (relation);
185                         }
186
187                         protected override void RemoveCore (DataRelation relation)
188                         {
189                                 base.RemoveCore (relation);
190                                 GetDataSet ().Relations.Remove (relation);
191                         }
192
193                         protected override ArrayList List {
194                                 get {
195                                         return base.List;
196                                 }
197                         }
198                 }
199
200                 private int defaultNameIndex;
201                 private bool inTransition;
202                 
203                 /// <summary>
204                 /// Initializes a new instance of the DataRelationCollection class.
205                 /// </summary>
206                 protected DataRelationCollection () 
207                         : base ()
208                 {
209                         defaultNameIndex = 1;
210                         inTransition = false;
211                 }
212
213                 /// <summary>
214                 /// Gets the DataRelation object specified by name.
215                 /// </summary>
216                 public abstract DataRelation this[string name]{get;}
217
218                 /// <summary>
219                 /// Gets the DataRelation object at the specified index.
220                 /// </summary>
221                 public abstract DataRelation this[int index]{get;}
222
223                 
224                 #region Add Methods
225                 private string GetNextDefaultRelationName ()
226                 {
227                         string defRelationName = "Relation";
228                         for (int index = 1; Contains (defRelationName); ++index) {
229                                 defRelationName = "Relation" + index;
230                         }
231                         return defRelationName;
232                 }
233
234                 /// <summary>
235                 /// Adds a DataRelation to the DataRelationCollection.
236                 /// </summary>
237                 /// <param name="relation">The DataRelation to add to the collection.</param>
238                 [MonoTODO]
239                 public void Add(DataRelation relation)
240                 {
241                         this.AddCore (relation);
242                         CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
243                         List.Add(relation);
244                         OnCollectionChanged(e);
245                 }
246
247                 /// <summary>
248                 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
249                 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
250                 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
251                 /// The CollectionChanged event is fired if it succeeds.
252                 /// </summary>
253                 /// <param name="parentColumn">parent column of relation.</param>
254                 /// <param name="childColumn">child column of relation.</param>
255                 /// <returns>The created DataRelation.</returns>
256                 public virtual DataRelation Add(DataColumn parentColumn, DataColumn childColumn)
257                 {       
258                         DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumn, childColumn);
259                         Add(dataRelation);
260                         return dataRelation;
261                 }
262
263                 /// <summary>
264                 /// Creates a relation given the parameters and adds it to the collection. The name is defaulted.
265                 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
266                 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
267                 /// The CollectionChanged event is raised if it succeeds.
268                 /// </summary>
269                 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
270                 /// <param name="childColumns">An array of child DataColumn objects.</param>
271                 /// <returns>The created DataRelation.</returns>
272                 public virtual DataRelation Add(DataColumn[] parentColumns, DataColumn[] childColumns)
273                 {
274                         DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumns, childColumns);
275                         Add(dataRelation);
276                         return dataRelation;
277                 }
278
279                 /// <summary>
280                 /// Creates a relation given the parameters and adds it to the collection.
281                 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
282                 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
283                 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
284                 /// The CollectionChanged event is raised if it succeeds.
285                 /// </summary>
286                 /// <param name="name">The name of the relation.</param>
287                 /// <param name="parentColumn">parent column of relation.</param>
288                 /// <returns>The created DataRelation.</returns>
289                 /// <returns></returns>
290                 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn)
291                 {
292                         //If no name was supplied, give it a default name.
293                         if (name == null || name == "") name = GetNextDefaultRelationName ();
294
295                         DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn);
296                         Add(dataRelation);
297                         return dataRelation;
298                 }
299
300                 /// <summary>
301                 /// Creates a DataRelation with the specified name, and arrays of parent and child columns, and adds it to the collection.
302                 /// </summary>
303                 /// <param name="name">The name of the DataRelation to create.</param>
304                 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
305                 /// <param name="childColumns">An array of child DataColumn objects.</param>
306                 /// <returns>The created DataRelation.</returns>
307                 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns)
308                 {
309                         //If no name was supplied, give it a default name.
310                         if (name == null || name == "") name = GetNextDefaultRelationName ();
311
312                         DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns);
313                         Add(dataRelation);
314                         return dataRelation;
315                 }
316
317                 /// <summary>
318                 /// Creates a relation given the parameters and adds it to the collection.
319                 /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection.
320                 /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive).
321                 /// An InvalidConstraintException is generated if the relation can't be created based on the parameters.
322                 /// The CollectionChanged event is raised if it succeeds.
323                 /// </summary>
324                 /// <param name="name">The name of the relation.</param>
325                 /// <param name="parentColumn">parent column of relation.</param>
326                 /// <param name="childColumn">child column of relation.</param>
327                 /// <param name="createConstraints">true to create constraints; otherwise false. (default is true)</param>
328                 /// <returns>The created DataRelation.</returns>
329                 public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn, bool createConstraints)
330                 {
331                         //If no name was supplied, give it a default name.
332                         if (name == null || name == "") name = GetNextDefaultRelationName ();
333
334                         DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn, createConstraints);
335                         Add(dataRelation);
336                         return dataRelation;
337                 }
338
339                 /// <summary>
340                 /// Creates a DataRelation with the specified name, arrays of parent and child columns, 
341                 /// and value specifying whether to create a constraint, and adds it to the collection.
342                 /// </summary>
343                 /// <param name="name">The name of the DataRelation to create.</param>
344                 /// <param name="parentColumns">An array of parent DataColumn objects.</param>
345                 /// <param name="childColumns">An array of child DataColumn objects.</param>
346                 /// <param name="createConstraints">true to create a constraint; otherwise false.</param>
347                 /// <returns>The created DataRelation.</returns>
348                 public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints)
349                 {
350                         //If no name was supplied, give it a default name.
351                         if (name == null || name == "") name = GetNextDefaultRelationName ();
352
353                         DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns, createConstraints);
354                         Add(dataRelation);
355                         return dataRelation;
356                 }
357                 #endregion
358         
359                 /// <summary>
360                 /// Performs verification on the table.
361                 /// </summary>
362                 /// <param name="relation">The relation to check.</param>
363                 [MonoTODO]
364                 protected virtual void AddCore(DataRelation relation)
365                 {
366                         if (relation == null)
367                         {
368                                 //TODO: Issue a good exception message.
369                                 throw new ArgumentNullException();
370                         }
371                         else if(List.IndexOf(relation) != -1)
372                         {
373                                 //TODO: Issue a good exception message.
374                                 throw new ArgumentException();
375                         }
376                         else if(List.Contains(relation.RelationName))
377                         {
378                                 //TODO: Issue a good exception message.
379                                 throw new DuplicateNameException("A Relation named " + relation.RelationName + " already belongs to this DataSet.");
380                         }
381                 }
382
383                 /// <summary>
384                 /// Copies the elements of the specified DataRelation array to the end of the collection.
385                 /// </summary>
386                 /// <param name="relations">The array of DataRelation objects to add to the collection.</param>
387                 public virtual void AddRange(DataRelation[] relations)
388                 {
389                         foreach (DataRelation relation in relations) Add(relation);
390                 }
391
392                 [MonoTODO]
393                 public virtual bool CanRemove(DataRelation relation)
394                 {
395                         //TODO: Implement.
396                         return false;
397                 }
398
399                 public virtual void Clear()
400                 {
401                         List.Clear();
402                 }
403
404                 public virtual bool Contains(string name)
405                 {
406                         return IndexOf(name) != -1;
407                 }
408
409                 private CollectionChangeEventArgs CreateCollectionChangeEvent (CollectionChangeAction action)
410                 {
411                         return new CollectionChangeEventArgs (action, this);
412                 }
413
414                 protected abstract DataSet GetDataSet();
415
416                 public virtual int IndexOf(DataRelation relation)
417                 {
418                         return List.IndexOf(relation);
419                 }
420
421                 public virtual int IndexOf(string relationName)
422                 {
423                         return List.IndexOf(this[relationName]);
424                 }
425
426                 protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent)
427                 {
428                         if (CollectionChanged != null)
429                                 CollectionChanged (this, ccevent);
430                 }
431
432                 [MonoTODO]
433                 protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs ccevent)
434                 {
435                         throw new NotImplementedException ();
436                 }
437
438                 public void Remove (DataRelation relation)
439                 {
440                         RemoveCore (relation);
441                         List.Remove (relation);
442                         OnCollectionChanged (CreateCollectionChangeEvent (CollectionChangeAction.Remove));
443                 }
444
445                 public void Remove (string name)
446                 {
447                         Remove ((DataRelation) List[IndexOf (name)]);
448                 }
449
450                 public void RemoveAt (int index)
451                 {
452                         List.RemoveAt (index);
453                 }
454
455                 [MonoTODO]
456                 protected virtual void RemoveCore(DataRelation relation)
457                 {
458                         // TODO: What have to be done?
459                 }
460
461                 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]
462                 public event CollectionChangeEventHandler CollectionChanged;
463         }
464 }