2 // System.Data.DataColumnCollection.cs
5 // Christopher Podurgiel (cpodurgiel@msn.com)
6 // Stuart Caborn <stuart.caborn@virgin.net>
7 // Tim Coleman (tim@timcoleman.com)
10 // Copyright (C) Tim Coleman, 2002
11 // Copyright (C) Daniel Morgan, 2003
15 using System.Collections;
16 using System.ComponentModel;
18 namespace System.Data {
21 [DefaultEvent ("CollectionChanged")]
22 public class DataColumnCollection : InternalDataCollectionBase
24 //table should be the DataTable this DataColumnCollection belongs to.
25 private DataTable parentTable = null;
27 // Internal Constructor. This Class can only be created from other classes in this assembly.
28 internal DataColumnCollection(DataTable table):base()
34 /// Gets the DataColumn from the collection at the specified index.
36 public virtual DataColumn this[int index]
40 return (DataColumn) base.List[index];
45 /// Gets the DataColumn from the collection with the specified name.
47 public virtual DataColumn this[string name]
51 foreach (DataColumn column in base.List)
53 if (String.Compare (column.ColumnName, name, true) == 0)
63 /// Gets a list of the DataColumnCollection items.
65 protected override ArrayList List
76 //DefaultValue set and AutoInc set check
77 //?Validate Expression??
78 //Name check and creation
80 //Check Unique if true then add a unique constraint
81 //?Notify Rows of new column ?
86 /// Creates and adds a DataColumn object to the DataColumnCollection.
88 /// <returns></returns>
89 public virtual DataColumn Add()
92 string defaultName = GetNextDefaultColumnName ();
93 DataColumn column = new DataColumn (defaultName);
94 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
96 column.SetTable(parentTable);
97 base.List.Add(column);
99 column.SetOrdinal(Count - 1);
100 OnCollectionChanged(e);
104 private string GetNextDefaultColumnName ()
106 string defColumnName = "Column1";
107 for (int index = 2; Contains (defColumnName); ++index) {
108 defColumnName = "Column" + index;
110 return defColumnName;
114 /// Creates and adds the specified DataColumn object to the DataColumnCollection.
116 /// <param name="column">The DataColumn to add.</param>
118 public void Add(DataColumn column)
122 throw new ArgumentNullException ("column", "'column' argument cannot be null.");
124 if (column.ColumnName.Equals(String.Empty))
126 column.ColumnName = GetNextDefaultColumnName ();
128 else if (Contains(column.ColumnName))
130 if (object.ReferenceEquals(this [column.ColumnName], column))
131 throw new ArgumentException ("Column '" + column.ColumnName + "' already belongs to this DataTable.");
133 throw new DuplicateNameException("A column named '" + column.ColumnName + "' already belongs to this DataTable.");
136 if (column.Table != null)
137 throw new ArgumentException ("Column '" + column.ColumnName + "' already belongs to another DataTable.");
139 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
141 column.SetTable (parentTable);
142 int ordinal = base.List.Add(column);
143 column.SetOrdinal (ordinal);
145 //add constraints if neccesary
149 UniqueConstraint uc = new UniqueConstraint(column);
150 parentTable.Constraints.Add(uc);
153 //TODO: add missing constraints. i.e. Primary/Foreign keys
155 OnCollectionChanged (e);
159 /// Creates and adds a DataColumn object with the specified name to the DataColumnCollection.
161 /// <param name="columnName">The name of the column.</param>
162 /// <returns>The newly created DataColumn.</returns>
163 public virtual DataColumn Add(string columnName)
165 if (columnName == null || columnName == String.Empty)
167 columnName = GetNextDefaultColumnName ();
170 DataColumn column = new DataColumn(columnName);
176 /// Creates and adds a DataColumn object with the specified name and type to the DataColumnCollection.
178 /// <param name="columnName">The ColumnName to use when cretaing the column.</param>
179 /// <param name="type">The DataType of the new column.</param>
180 /// <returns>The newly created DataColumn.</returns>
181 public virtual DataColumn Add(string columnName, Type type)
183 if (columnName == null || columnName == "")
185 columnName = GetNextDefaultColumnName ();
188 DataColumn column = new DataColumn(columnName, type);
194 /// Creates and adds a DataColumn object with the specified name, type, and expression to the DataColumnCollection.
196 /// <param name="columnName">The name to use when creating the column.</param>
197 /// <param name="type">The DataType of the new column.</param>
198 /// <param name="expression">The expression to assign to the Expression property.</param>
199 /// <returns>The newly created DataColumn.</returns>
200 public virtual DataColumn Add(string columnName, Type type, string expression)
202 if (columnName == null || columnName == "")
204 columnName = GetNextDefaultColumnName ();
207 DataColumn column = new DataColumn(columnName, type, expression);
213 /// Copies the elements of the specified DataColumn array to the end of the collection.
215 /// <param name="columns">The array of DataColumn objects to add to the collection.</param>
216 public void AddRange(DataColumn[] columns)
218 foreach (DataColumn column in columns)
226 /// Checks whether a given column can be removed from the collection.
228 /// <param name="column">A DataColumn in the collection.</param>
229 /// <returns>true if the column can be removed; otherwise, false.</returns>
230 public bool CanRemove(DataColumn column)
233 //Check that the column does not have a null reference.
240 //Check that the column is part of this collection.
241 if (!Contains(column.ColumnName))
248 //Check if this column is part of a relationship. (this could probably be written better)
249 foreach (DataRelation childRelation in parentTable.ChildRelations)
251 foreach (DataColumn childColumn in childRelation.ChildColumns)
253 if (childColumn == column)
259 foreach (DataColumn parentColumn in childRelation.ParentColumns)
261 if (parentColumn == column)
268 //Check if this column is part of a relationship. (this could probably be written better)
269 foreach (DataRelation parentRelation in parentTable.ParentRelations)
271 foreach (DataColumn childColumn in parentRelation.ChildColumns)
273 if (childColumn == column)
279 foreach (DataColumn parentColumn in parentRelation.ParentColumns)
281 if (parentColumn == column)
289 //Check if another column's expression depends on this column.
291 foreach (DataColumn dataColumn in List)
293 if (dataColumn.Expression.ToString().IndexOf(column.ColumnName) > 0)
299 //TODO: check constraints
305 /// Clears the collection of any columns.
309 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this);
312 // FIXME: Hmm... This loop could look little nicer :)
313 foreach (DataColumn Col in List) {
315 foreach (DataRelation Rel in Col.Table.ParentRelations) {
317 foreach (DataColumn Col2 in Rel.ParentColumns) {
318 if (Object.ReferenceEquals (Col, Col2))
319 throw new ArgumentException ("Cannot remove this column, because " +
320 "it is part of the parent key for relationship " +
321 Rel.RelationName + ".");
324 foreach (DataColumn Col2 in Rel.ChildColumns) {
325 if (Object.ReferenceEquals (Col, Col2))
326 throw new ArgumentException ("Cannot remove this column, because " +
327 "it is part of the parent key for relationship " +
328 Rel.RelationName + ".");
333 foreach (DataRelation Rel in Col.Table.ChildRelations) {
335 foreach (DataColumn Col2 in Rel.ParentColumns) {
336 if (Object.ReferenceEquals (Col, Col2))
337 throw new ArgumentException ("Cannot remove this column, because " +
338 "it is part of the parent key for relationship " +
339 Rel.RelationName + ".");
342 foreach (DataColumn Col2 in Rel.ChildColumns) {
343 if (Object.ReferenceEquals (Col, Col2))
344 throw new ArgumentException ("Cannot remove this column, because " +
345 "it is part of the parent key for relationship " +
346 Rel.RelationName + ".");
353 OnCollectionChanged(e);
358 /// Checks whether the collection contains a column with the specified name.
360 /// <param name="name">The ColumnName of the column to check for.</param>
361 /// <returns>true if a column exists with this name; otherwise, false.</returns>
362 public bool Contains(string name)
364 return (IndexOf(name) != -1);
368 /// Gets the index of a column specified by name.
370 /// <param name="column">The name of the column to return.</param>
371 /// <returns>The index of the column specified by column if it is found; otherwise, -1.</returns>
372 public virtual int IndexOf(DataColumn column)
374 return base.List.IndexOf(column);
378 /// Gets the index of the column with the given name (the name is not case sensitive).
380 /// <param name="columnName">The name of the column to find.</param>
381 /// <returns>The zero-based index of the column with the specified name, or -1 if the column doesn't exist in the collection.</returns>
382 public int IndexOf(string columnName)
385 DataColumn column = this[columnName];
389 return IndexOf(column);
398 /// Raises the OnCollectionChanged event.
400 /// <param name="ccevent">A CollectionChangeEventArgs that contains the event data.</param>
401 protected virtual void OnCollectionChanged(CollectionChangeEventArgs ccevent)
403 if (CollectionChanged != null)
405 CollectionChanged(this, ccevent);
410 /// Raises the OnCollectionChanging event.
412 /// <param name="ccevent">A CollectionChangeEventArgs that contains the event data.</param>
413 protected internal virtual void OnCollectionChanging(CollectionChangeEventArgs ccevent)
415 if (CollectionChanged != null)
417 //FIXME: this is not right
418 //CollectionChanged(this, ccevent);
419 throw new NotImplementedException();
424 /// Removes the specified DataColumn object from the collection.
426 /// <param name="column">The DataColumn to remove.</param>
427 public void Remove(DataColumn column)
429 if (IndexOf (column) == -1)
430 throw new ArgumentException ("Cannot remove a column that doesn't belong to this table.");
432 //TODO: can remove first with exceptions
433 //and OnChanging Event
434 CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Remove, this);
436 int ordinal = column.Ordinal;
437 base.List.Remove(column);
439 //Update the ordinals
440 for( int i = ordinal ; i < this.Count ; i ++ )
442 this[i].SetOrdinal( i );
445 OnCollectionChanged(e);
450 /// Removes the DataColumn object with the specified name from the collection.
452 /// <param name="name">The name of the column to remove.</param>
453 public void Remove(string name)
455 DataColumn column = this[name];
458 throw new ArgumentException ("Column '" + name + "' does not belong to table test_table.");
464 /// Removes the column at the specified index from the collection.
466 /// <param name="index">The index of the column to remove.</param>
467 public void RemoveAt(int index)
470 throw new IndexOutOfRangeException ("Cannot find column " + index + ".");
472 DataColumn column = this[index];
477 /// Occurs when the columns collection changes, either by adding or removing a column.
479 public event CollectionChangeEventHandler CollectionChanged;