2 // System.Data.DataTableCollection.cs
5 // Christopher Podurgiel (cpodurgiel@msn.com)
6 // Tim Coleman <tim@timcoleman.com>
9 // (C) Copyright 2002 Tim Coleman
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.ComponentModel;
38 using System.Globalization;
40 using System.Runtime.Serialization;
41 using System.Runtime.Serialization.Formatters.Binary;
46 /// Represents the collection of tables for the DataSet.
48 [Editor ("Microsoft.VSDesigner.Data.Design.TablesCollectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner,
49 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
50 [DefaultEvent ("CollectionChanged")]
51 [ListBindable (false)]
52 public partial class DataTableCollection : InternalDataCollectionBase {
54 DataTable[] mostRecentTables;
58 internal DataTableCollection (DataSet dataSet)
61 this.dataSet = dataSet;
68 public DataTable this [int index] {
70 if (index < 0 || index >= List.Count)
71 throw new IndexOutOfRangeException (String.Format ("Cannot find table {0}", index));
72 return (DataTable)(List [index]);
76 public DataTable this [string name] {
78 int index = IndexOf (name, true);
79 return index < 0 ? null : (DataTable) List [index];
83 protected override ArrayList List {
84 get { return base.List; }
97 DataTable Table = new DataTable ();
106 void Add (DataTable table)
108 OnCollectionChanging (new CollectionChangeEventArgs (CollectionChangeAction.Add, table));
109 // check if the reference is a null reference
111 throw new ArgumentNullException ("table");
113 // check if the list already contains this tabe.
114 if (List.Contains (table))
115 throw new ArgumentException ("DataTable already belongs to this DataSet.");
117 // check if table is part of another DataSet
118 if (table.DataSet != null && table.DataSet != this.dataSet)
119 throw new ArgumentException ("DataTable already belongs to another DataSet");
121 // if the table name is null or empty string.
123 if (table.TableName == null || table.TableName == string.Empty)
126 // check if the collection has a table with the same name.
128 int tmp = IndexOf (table.TableName);
130 int tmp = IndexOf (table.TableName, table.Namespace);
132 // if we found a table with same name we have to check
133 // that it is the same case.
134 // indexof can return a table with different case letters.
136 table.TableName == this [tmp].TableName)
137 throw new DuplicateNameException ("A DataTable named '" + table.TableName + "' already belongs to this DataSet.");
140 table.dataSet = dataSet;
141 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, table));
148 DataTable Add (string name)
150 DataTable table = new DataTable (name);
155 public void AddRange (DataTable [] tables)
157 if (dataSet != null && dataSet.InitInProgress) {
158 mostRecentTables = tables;
165 foreach (DataTable table in tables) {
172 internal void PostAddRange ()
174 if (mostRecentTables == null)
177 foreach (DataTable table in mostRecentTables){
182 mostRecentTables = null;
185 public bool CanRemove (DataTable table)
187 return CanRemove (table, false);
195 public bool Contains (string name)
197 return (-1 != IndexOf (name, false));
204 int IndexOf (DataTable table)
206 return List.IndexOf (table);
213 int IndexOf (string tableName)
215 return IndexOf (tableName, false);
218 public void Remove (DataTable table)
220 OnCollectionChanging (new CollectionChangeEventArgs (CollectionChangeAction.Remove, table));
221 if (CanRemove (table, true))
222 table.dataSet = null;
225 table.dataSet = null;
226 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, table));
229 public void Remove (string name)
231 int index = IndexOf (name, false);
233 throw new ArgumentException ("Table " + name + " does not belong to this DataSet");
237 public void RemoveAt (int index)
239 Remove (this [index]);
244 #region Protected methods
247 protected internal virtual
251 void OnCollectionChanging (CollectionChangeEventArgs ccevent)
253 if (CollectionChanging != null)
254 CollectionChanging (this, ccevent);
262 void OnCollectionChanged (CollectionChangeEventArgs ccevent)
264 if (CollectionChanged != null)
265 CollectionChanged (this, ccevent);
270 #region Private methods
272 private int IndexOf (string name, bool error, int start)
274 int count = 0, match = -1;
275 for (int i = start; i < List.Count; i++) {
276 String name2 = ((DataTable) List[i]).TableName;
277 if (String.Compare (name, name2, false, dataSet.Locale) == 0)
279 if (String.Compare (name, name2, true, dataSet.Locale) == 0) {
286 if (count > 1 && error)
287 throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
292 /// gives name to Table (Table1, Table2, Table3,...)
294 private void NameTable (DataTable Table)
296 string Name = "Table";
298 while (Contains (Name + i))
301 Table.TableName = Name + i;
304 // check if a table can be removed from this collectiuon.
305 // if the table can not be remved act according to throwException parameter.
306 // if it is true throws an Exception, else return false.
307 private bool CanRemove (DataTable table, bool throwException)
309 // check if table is null reference
312 throw new ArgumentNullException ("table");
316 // check if the table has the same DataSet as this collection.
317 if (table.DataSet != this.dataSet) {
320 throw new ArgumentException ("Table " + table.TableName + " does not belong to this DataSet.");
323 // check the table has a relation attached to it.
324 if (table.ParentRelations.Count > 0 || table.ChildRelations.Count > 0) {
327 throw new ArgumentException ("Cannot remove a table that has existing relations. Remove relations first.");
330 // now we check if any ForeignKeyConstraint is referncing 'table'.
331 foreach (Constraint c in table.Constraints) {
332 UniqueConstraint uc = c as UniqueConstraint;
334 if (uc.ChildConstraint == null)
339 RaiseForeignKeyReferenceException (table.TableName, uc.ChildConstraint.ConstraintName);
342 ForeignKeyConstraint fc = c as ForeignKeyConstraint;
348 RaiseForeignKeyReferenceException (table.TableName, fc.ConstraintName);
354 private void RaiseForeignKeyReferenceException (string table, string constraint)
356 throw new ArgumentException (String.Format ("Cannot remove table {0}, because it is referenced" +
357 " in ForeignKeyConstraint {1}. Remove the constraint first.",
361 #endregion // Private methods
365 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]
366 public event CollectionChangeEventHandler CollectionChanged;
368 public event CollectionChangeEventHandler CollectionChanging;
374 sealed partial class DataTableCollection {
375 public DataTable this [string name, string tableNamespace] {
377 int index = IndexOf (name, tableNamespace, true);
378 return index < 0 ? null : (DataTable) List [index];
382 public DataTable Add (string name, string tableNamespace)
384 DataTable table = new DataTable (name, tableNamespace);
389 public bool Contains (string name, string tableNamespace)
391 return (IndexOf (name, tableNamespace) != -1);
394 public int IndexOf (string tableName, string tableNamespace)
396 if (tableNamespace == null)
397 throw new ArgumentNullException ("'tableNamespace' argument cannot be null.",
399 return IndexOf (tableName, tableNamespace, false);
402 public void Remove (string name, string tableNamespace)
404 int index = IndexOf (name, tableNamespace, true);
406 throw new ArgumentException ("Table " + name + " does not belong to this DataSet");
411 private int IndexOf (string name, string ns, bool error)
413 int index = -1, count = 0, match = -1;
415 index = IndexOf (name, error, index+1);
425 } else if (this [index].Namespace.Equals (ns))
428 } while (index != -1 && index < Count);
433 if (count == 0 || !error)
436 throw new ArgumentException ("The given name '" + name + "' matches atleast two names" +
437 "in the collection object with different namespaces");
440 private int IndexOf (string name, bool error)
442 return IndexOf (name, null, error);
445 public void CopyTo (DataTable [] array, int index)
447 CopyTo ((Array) array, index);
450 internal void BinarySerialize_Schema (SerializationInfo si)
452 si.AddValue ("DataSet.Tables.Count", Count);
453 for (int i = 0; i < Count; i++) {
454 DataTable dt = (DataTable) List [i];
456 if (dt.dataSet != dataSet)
457 throw new SystemException ("Internal Error: inconsistent DataTable");
459 MemoryStream ms = new MemoryStream ();
460 BinaryFormatter bf = new BinaryFormatter ();
461 bf.Serialize (ms, dt);
462 byte [] serializedStream = ms.ToArray ();
464 si.AddValue ("DataSet.Tables_" + i, serializedStream, typeof (Byte []));
468 internal void BinarySerialize_Data (SerializationInfo si)
470 for (int i = 0; i < Count; i++) {
471 DataTable dt = (DataTable) List [i];
472 for (int j = 0; j < dt.Columns.Count; j++) {
473 si.AddValue ("DataTable_" + i + ".DataColumn_" + j + ".Expression",
474 dt.Columns[j].Expression);
476 dt.BinarySerialize (si, "DataTable_" + i + ".");
482 partial class DataTableCollection {
483 private int IndexOf (string name, bool error)
485 return IndexOf (name, error, 0);