2004-03-03 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.Data / System.Data / DataTableCollection.cs
1 //
2 // System.Data.DataTableCollection.cs
3 //
4 // Authors:
5 //   Christopher Podurgiel (cpodurgiel@msn.com)
6 //   Tim Coleman <tim@timcoleman.com>
7 //
8 // (C) Chris Podurgiel
9 // (C) Copyright 2002 Tim Coleman
10 //
11
12 using System;
13 using System.Collections;
14 using System.ComponentModel;
15 using System.Globalization;
16
17 namespace System.Data {
18         /// <summary>
19         /// Represents the collection of tables for the DataSet.
20         /// </summary>
21         [Editor]
22         [DefaultEvent ("CollectionChanged")]
23         [ListBindable (false)]
24         [Serializable]
25         public class DataTableCollection : InternalDataCollectionBase
26         {
27                 DataSet dataSet;
28                 
29                 #region Constructors 
30
31                 internal DataTableCollection (DataSet dataSet)
32                         : base ()
33                 {
34                         this.dataSet = dataSet;
35                 }
36                 
37                 #endregion
38                 
39                 #region Properties
40
41                 public DataTable this[int index] {
42                         get { return (DataTable)(list[index]); }
43                 }
44
45                 public DataTable this[string name] {
46                         get { 
47                                 int index = IndexOf (name, true);
48                                 return index < 0 ? null : (DataTable) list[index];
49                         }
50                 }
51
52 #if NET_1_2
53                 [MonoTODO]
54                 public DataTable this [string name, string tbNamespace] {
55                         get { throw new NotImplementedException (); }
56                 }
57 #endif
58
59                 protected override ArrayList List {
60                         get { return list; }
61                 }
62
63                 #endregion
64         
65                 #region Methods 
66
67                 public virtual DataTable Add () 
68                 {
69                         DataTable Table = new DataTable ();
70                         Add (Table);
71                         return Table;
72                 }
73
74                 public virtual void Add (DataTable table) 
75                 {
76                         
77                         // check if the reference is a null reference
78                         if(table == null)
79                                 throw new ArgumentNullException("table");
80             
81                         // check if the list already contains this tabe.
82                         if(list.Contains(table))
83                                 throw new ArgumentException("DataTable already belongs to this DataSet.");
84             
85                         // if the table name is null or empty string.
86                         // give her a name. 
87                         if (table.TableName == null || table.TableName == string.Empty)
88                                 NameTable (table);
89                     
90                         // check if the collection has a table with the same name.
91                         int tmp = IndexOf(table.TableName);
92                         // if we found a table with same name we have to check
93                         // that it is the same case.
94                         // indexof can return a table with different case letters.
95                         if (tmp != -1)
96                         {
97                                 if(table.TableName == this[tmp].TableName)
98                                         throw new DuplicateNameException("A DataTable named '" + table.TableName + "' already belongs to this DataSet.");
99                         }
100         
101                         list.Add (table);
102                         table.dataSet = dataSet;
103                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, table));
104                 }
105
106                 public virtual DataTable Add (string name) 
107                 {
108                         DataTable table = new DataTable (name);
109                         this.Add (table);
110                         return table;
111                 }
112
113 #if NET_1_2
114                 public virtual DataTable Add (string name, string tbNamespace)
115                 {
116                         DataTable table = new DataTable (name, tbNamespace);
117                         this.Add (table);
118                         return table;
119                 }
120 #endif
121
122                 public void AddRange (DataTable[] tables) 
123                 {
124                         foreach (DataTable table in tables)
125                                 this.Add (table);
126                 }
127
128                 [MonoTODO]
129                 public bool CanRemove (DataTable table) 
130                 {
131                         return CanRemove(table, false);
132                 }
133
134                 public void Clear () 
135                 {
136                         list.Clear ();
137                 }
138
139                 public bool Contains (string name) 
140                 {
141                         return (-1 != IndexOf (name, false));
142                 }
143
144                 public virtual int IndexOf (DataTable table) 
145                 {
146                         return list.IndexOf (table);
147                 }
148
149                 public virtual int IndexOf (string name) 
150                 {
151                         return IndexOf (name, false);
152                 }
153
154                 public void Remove (DataTable table) 
155                 {
156                         CanRemove(table, true);
157                         list.Remove(table);
158                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, table));
159                 }
160
161                 public void Remove (string name) 
162                 {
163                         Remove (this [name]);
164                 }
165
166                 public void RemoveAt (int index) 
167                 {
168                         DataTable t = this[index];
169                         CanRemove(t, true);
170                         list.RemoveAt (index);
171                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, t));
172                 }
173
174                 #endregion
175
176                 #region Protected methods
177
178                 protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs Args)
179                 {
180                         if (CollectionChanging != null)
181                                 CollectionChanging (this, Args);
182                 }
183
184                 protected virtual void OnCollectionChanged (CollectionChangeEventArgs Args)
185                 {
186                         if (CollectionChanged != null)
187                                 CollectionChanged (this, Args);
188                 }
189
190                 #endregion
191
192                 #region Private methods
193
194                 private int IndexOf (string name, bool error)
195                 {
196                         int count = 0, match = -1;
197                         for (int i = 0; i < list.Count; i++)
198                         {
199                                 String name2 = ((DataTable) list[i]).TableName;
200                                 if (String.Compare (name, name2, true) == 0)
201                                 {
202                                         if (String.Compare (name, name2, false) == 0)
203                                                 return i;
204                                         match = i;
205                                         count++;
206                                 }
207                         }
208                         if (count == 1)
209                                 return match;
210                         if (count > 1 && error)
211                                 throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
212                         return -1;
213                 }
214
215                 /// <summary>
216                 /// gives name to Table (Table1, Table2, Table3,...)
217                 /// </summary>
218                 private void NameTable (DataTable Table)
219                 {
220                         string Name = "Table";
221                         int i = 1;
222                         while (Contains (Name + i))
223                                 i++;
224
225                         Table.TableName = Name + i;                            
226                 }
227                 
228                 // check if a table can be removed from this collectiuon.
229                 // if the table can not be remved act according to throwException parameter.
230                 // if it is true throws an Exception, else return false.
231                 private bool CanRemove(DataTable table, bool throwException)
232                 {
233                         // check if table is null reference
234                         if (table == null)
235                         {
236                                 if(throwException)
237                                         throw new ArgumentNullException("table");
238                                 return false;
239                         }
240                         
241                         // check if the table has the same DataSet as this collection.
242                         if(table.DataSet != this.dataSet)
243                         {
244                                 if(throwException)
245                                         throw new ArgumentException("Table " + table.TableName + " does not belong to this DataSet.");
246                                 return false;
247                         }
248                         
249                         // check the table has a relation attached to it.
250                         if (table.ParentRelations.Count > 0 || table.ChildRelations.Count > 0)
251                         {
252                                 if(throwException)
253                                         throw new ArgumentException("Cannot remove a table that has existing relations. Remove relations first.");
254                                 return false;
255                         }
256                         
257
258                         // now we check if any ForeignKeyConstraint is referncing 'table'.
259                         IEnumerator tableEnumerator = this.dataSet.Tables.GetEnumerator();
260                         
261                         // loop on all tables in dataset
262                         while (tableEnumerator.MoveNext())
263                         {
264                                 IEnumerator constraintEnumerator = ((DataTable) tableEnumerator.Current).Constraints.GetEnumerator();
265                                 // loop on all constrains in the current table
266                                 while (constraintEnumerator.MoveNext())
267                                 {
268                                         Object o = constraintEnumerator.Current;
269                                         // we only check ForeignKeyConstraint
270                                         if (o is ForeignKeyConstraint)
271                                         {
272                                                 ForeignKeyConstraint fc = (ForeignKeyConstraint) o;
273                                                 if(fc.Table == table || fc.RelatedTable == table)
274                                                 {
275                                                         if(throwException)
276                                                                 throw new ArgumentException("Cannot remove table " + table.TableName + ", because it referenced in ForeignKeyConstraint " + fc.ConstraintName + ". Remove the constraint first.");
277                                                         return false;
278                                                 }
279                                         }
280                                 }
281                         }
282
283                         return true;
284                 }
285
286                 #endregion // Private methods
287
288                 #region Events
289
290                 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]             
291                 public event CollectionChangeEventHandler CollectionChanged;
292
293                 public event CollectionChangeEventHandler CollectionChanging;
294
295                 #endregion
296         }
297 }