2 // System.Data.DataTable.cs
5 // Franklin Wise <gracenote@earthlink.net>
6 // Christopher Podurgiel (cpodurgiel@msn.com)
7 // Daniel Morgan <danmorg@sc.rr.com>
8 // Rodrigo Moya <rodrigo@ximian.com>
9 // Tim Coleman (tim@timcoleman.com)
10 // Ville Palo <vi64pa@koti.soon.fi>
12 // (C) Chris Podurgiel
13 // (C) Ximian, Inc 2002
14 // Copyright (C) Tim Coleman, 2002
18 using System.Collections;
19 using System.ComponentModel;
20 using System.Globalization;
21 using System.Runtime.Serialization;
23 namespace System.Data {
26 [DefaultEvent ("RowChanging")]
27 [DefaultProperty ("TableName")]
28 [DesignTimeVisible (false)]
30 public class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable
32 internal DataSet dataSet;
34 private bool _caseSensitive;
35 private DataColumnCollection _columnCollection;
36 private ConstraintCollection _constraintCollection;
37 private DataView _defaultView;
39 private string _displayExpression;
40 private PropertyCollection _extendedProperties;
41 private bool _hasErrors;
42 private CultureInfo _locale;
43 private int _minimumCapacity;
44 private string _nameSpace;
45 private DataRelationCollection _childRelations;
46 private DataRelationCollection _parentRelations;
47 private string _prefix;
48 private DataColumn[] _primaryKey;
49 private DataRowCollection _rows;
51 private string _tableName;
52 private bool _containsListCollection;
53 private string _encodedTableName;
56 /// Initializes a new instance of the DataTable class with no arguments.
62 _columnCollection = new DataColumnCollection(this);
63 _constraintCollection = new ConstraintCollection();
64 _extendedProperties = new PropertyCollection();
67 _caseSensitive = false; //default value
68 _displayExpression = null;
71 _rows = new DataRowCollection (this);
72 _locale = CultureInfo.CurrentCulture;
74 //LAMESPEC: spec says 25 impl does 50
75 _minimumCapacity = 50;
77 _childRelations = new DataRelationCollection.DataTableRelationCollection (this);
78 _parentRelations = new DataRelationCollection.DataTableRelationCollection (this);
81 _defaultView = new DataView(this);
85 /// Intitalizes a new instance of the DataTable class with the specified table name.
88 public DataTable(string tableName) : this ()
90 _tableName = tableName;
94 /// Initializes a new instance of the DataTable class with the SerializationInfo and the StreamingContext.
98 protected DataTable(SerializationInfo info, StreamingContext context)
102 // TODO: Add constructor logic here
107 /// Indicates whether string comparisons within the table are case-sensitive.
109 [DataSysDescription ("Indicates whether comparing strings within the table is case sensitive.")]
110 public bool CaseSensitive {
111 get { return _caseSensitive; }
112 set { _caseSensitive = value; }
116 internal void ChangedDataColumn (DataRow dr, DataColumn dc, object pv)
118 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
122 internal void ChangingDataColumn (DataRow dr, DataColumn dc, object pv)
124 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
125 OnColumnChanging (e);
128 internal void DeletedDataRow (DataRow dr, DataRowAction action)
130 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
134 internal void ChangedDataRow (DataRow dr, DataRowAction action)
136 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
141 /// Gets the collection of child relations for this DataTable.
144 [DataSysDescription ("Returns the child relations for this table.")]
145 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
146 public DataRelationCollection ChildRelations {
148 return _childRelations;
153 /// Gets the collection of columns that belong to this table.
155 [DataCategory ("Data")]
156 [DataSysDescription ("The collection that holds the columns for this table.")]
157 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
158 public DataColumnCollection Columns {
159 get { return _columnCollection; }
163 /// Gets the collection of constraints maintained by this table.
165 [DataCategory ("Data")]
166 [DataSysDescription ("The collection that holds the constraints for this table.")]
167 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
168 public ConstraintCollection Constraints {
169 get { return _constraintCollection; }
173 /// Gets the DataSet that this table belongs to.
176 [DataSysDescription ("Indicates the DataSet to which this table belongs.")]
177 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
178 public DataSet DataSet {
179 get { return dataSet; }
185 /// Gets a customized view of the table which may
186 /// include a filtered view, or a cursor position.
190 [DataSysDescription ("This is the default DataView for the table.")]
191 public DataView DefaultView {
192 get { return _defaultView; }
197 /// Gets or sets the expression that will return
198 /// a value used to represent this table in the user interface.
200 [DataCategory ("Data")]
201 [DataSysDescription ("The expression used to compute the data-bound value of this row.")]
203 public string DisplayExpression {
204 get { return "" + _displayExpression; }
205 set { _displayExpression = value; }
209 /// Gets the collection of customized user information.
212 [DataCategory ("Data")]
213 [DataSysDescription ("The collection that holds custom user information.")]
214 public PropertyCollection ExtendedProperties {
215 get { return _extendedProperties; }
219 /// Gets a value indicating whether there are errors in
220 /// any of the_rows in any of the tables of the DataSet to
221 /// which the table belongs.
224 [DataSysDescription ("Returns whether the table has errors.")]
225 public bool HasErrors {
226 get { return _hasErrors; }
230 /// Gets or sets the locale information used to
231 /// compare strings within the table.
233 [DataSysDescription ("Indicates a locale under which to compare strings within the table.")]
234 public CultureInfo Locale {
235 get { return _locale; }
236 set { _locale = value; }
240 /// Gets or sets the initial starting size for this table.
242 [DataCategory ("Data")]
243 [DataSysDescription ("Indicates an initial starting size for this table.")]
245 public int MinimumCapacity {
246 get { return _minimumCapacity; }
247 set { _minimumCapacity = value; }
251 /// Gets or sets the namespace for the XML represenation
252 /// of the data stored in the DataTable.
254 [DataCategory ("Data")]
255 [DataSysDescription ("Indicates the XML uri namespace for the elements contained in this table.")]
256 public string Namespace {
257 get { return "" + _nameSpace; }
258 set { _nameSpace = value; }
262 /// Gets the collection of parent relations for
266 [DataSysDescription ("Returns the parent relations for this table.")]
267 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
268 public DataRelationCollection ParentRelations {
270 return _parentRelations;
275 /// Gets or sets the namespace for the XML represenation
276 /// of the data stored in the DataTable.
278 [DataCategory ("Data")]
279 [DataSysDescription ("Indicates the Prefix of the namespace used for this table in XML representation.")]
281 public string Prefix {
282 get { return "" + _prefix; }
283 set { _prefix = value; }
287 /// Gets or sets an array of columns that function as
288 /// primary keys for the data table.
290 [DataCategory ("Data")]
291 [DataSysDescription ("Indicates the column(s) that represent the primary key for this table.")]
292 public DataColumn[] PrimaryKey
295 UniqueConstraint uc = UniqueConstraint.GetPrimaryKeyConstraint( Constraints);
296 if (null == uc) return new DataColumn[] {};
301 //YUK: msft removes a previous unique constraint if it is flagged as a pk
302 //when a new pk is set
304 //clear Primary Key if value == null
307 UniqueConstraint.SetAsPrimaryKey(this.Constraints, null);
312 //Does constraint exist for these columns
313 UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet(
314 this.Constraints, (DataColumn[]) value);
316 //if constraint doesn't exist for columns
317 //create new unique primary key constraint
320 uc = new UniqueConstraint( (DataColumn[]) value, true);
322 else //set existing constraint as the new primary key
324 UniqueConstraint.SetAsPrimaryKey(this.Constraints, uc);
331 /// Gets the collection of_rows that belong to this table.
334 [DataSysDescription ("Indicates the collection that holds the rows of data for this table.")]
335 public DataRowCollection Rows {
336 get { return _rows; }
340 /// Gets or sets an System.ComponentModel.ISite
341 /// for the DataTable.
344 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
345 public override ISite Site {
346 get { return _site; }
347 set { _site = value; }
351 /// Gets or sets the name of the the DataTable.
353 [DataCategory ("Data")]
354 [DataSysDescription ("Indicates the name used to look up this table in the Tables collection of a DataSet.")]
356 [RefreshProperties (RefreshProperties.All)]
357 public string TableName {
358 get { return "" + _tableName; }
359 set { _tableName = value; }
362 bool IListSource.ContainsListCollection {
364 // the collection is a DataView
370 /// Commits all the changes made to this table since the
371 /// last time AcceptChanges was called.
374 public void AcceptChanges()
377 //FIXME: Do we need to validate anything here or
378 //try to catch any errors to deal with them?
380 foreach(DataRow myRow in _rows)
382 myRow.AcceptChanges();
388 /// Begins the initialization of a DataTable that is used
389 /// on a form or used by another component. The initialization
390 /// occurs at runtime.
393 public void BeginInit()
398 /// Turns off notifications, index maintenance, and
399 /// constraints while loading data.
403 public void BeginLoadData()
408 /// Clears the DataTable of all data.
417 /// Clones the structure of the DataTable, including
418 /// all DataTable schemas and constraints.
422 public virtual DataTable Clone()
424 DataTable Copy = new DataTable ();
425 CopyProperties (Copy);
430 /// Computes the given expression on the current_rows that
431 /// pass the filter criteria.
435 public object Compute(string expression, string filter)
437 //FIXME: //Do a real compute
443 /// Copies both the structure and data for this DataTable.
446 public DataTable Copy()
448 DataTable Copy = new DataTable ();
451 CopyProperties (Copy);
453 foreach (DataRow Row in Rows) {
454 DataRow NewRow = Copy.NewRow ();
455 NewRow.RowError = Row.RowError;
456 foreach (DataColumn C in Copy.Columns) {
457 NewRow [C.ColumnName] = Row [C.ColumnName];
459 Copy.Rows.Add (NewRow);
466 private void CopyProperties (DataTable Copy)
468 Copy.CaseSensitive = CaseSensitive;
469 // Copy.ChildRelations
474 Copy.DisplayExpression = DisplayExpression;
475 // Copy.ExtendedProperties
476 Copy.Locale = Locale;
477 Copy.MinimumCapacity = MinimumCapacity;
478 Copy.Namespace = Namespace;
479 // Copy.ParentRelations
480 Copy.Prefix = Prefix;
481 //Copy.PrimaryKey = PrimaryKey;
483 Copy.TableName = TableName;
486 foreach (DataColumn Column in Columns) {
487 Copy.Columns.Add (CopyColumn (Column));
492 /// Ends the initialization of a DataTable that is used
493 /// on a form or used by another component. The
494 /// initialization occurs at runtime.
497 public void EndInit()
502 /// Turns on notifications, index maintenance, and
503 /// constraints after loading data.
507 public void EndLoadData()
512 /// Gets a copy of the DataTable that contains all
513 /// changes made to it since it was loaded or
514 /// AcceptChanges was last called.
517 public DataTable GetChanges()
524 /// Gets a copy of the DataTable containing all
525 /// changes made to it since it was last loaded, or
526 /// since AcceptChanges was called, filtered by DataRowState.
529 public DataTable GetChanges(DataRowState rowStates)
536 /// Gets an array of DataRow objects that contain errors.
540 public DataRow[] GetErrors()
542 throw new NotImplementedException ();
546 /// This member supports the .NET Framework infrastructure
547 /// and is not intended to be used directly from your code.
550 protected virtual DataTable CreateInstance()
552 return Activator.CreateInstance(this.GetType(), true) as DataTable;
556 /// This member supports the .NET Framework infrastructure
557 /// and is not intended to be used directly from your code.
560 protected virtual Type GetRowType()
562 return typeof (DataRow);
566 /// This member supports the .NET Framework infrastructure
567 /// and is not intended to be used directly from your code.
569 /// Used for Data Binding between System.Web.UI. controls
572 /// System.Windows.Forms controls like a DataGrid
574 IList IListSource.GetList()
576 IList list = (IList) _defaultView;
581 /// Copies a DataRow into a DataTable, preserving any
582 /// property settings, as well as original and current values.
585 public void ImportRow(DataRow row)
590 /// This member supports the .NET Framework infrastructure
591 /// and is not intended to be used directly from your code.
595 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
600 /// Finds and updates a specific row. If no matching row
601 /// is found, a new row is created using the given values.
604 public DataRow LoadDataRow(object[] values, bool fAcceptChanges)
607 if (PrimaryKey.Length == 0) {
608 row = Rows.Add (values);
610 row.AcceptChanges ();
613 throw new NotImplementedException ();
618 /// Creates a new DataRow with the same schema as the table.
620 public DataRow NewRow()
622 return this.NewRowFromBuilder (new DataRowBuilder (this, 0, 0));
626 /// This member supports the .NET Framework infrastructure
627 /// and is not intended to be used directly from your code.
629 protected internal DataRow[] NewRowArray(int size)
631 return (DataRow[]) Array.CreateInstance (GetRowType(), size);
635 /// Creates a new row from an existing row.
638 protected virtual DataRow NewRowFromBuilder(DataRowBuilder builder)
640 return new DataRow (builder);
645 /// Rolls back all changes that have been made to the
646 /// table since it was loaded, or the last time AcceptChanges
651 public void RejectChanges()
654 //foreach(DataRow myRow in _rows)
656 for (int i = _rows.Count - 1; i >= 0; i--) {
657 DataRow row = _rows [i];
658 if (row.RowState != DataRowState.Unchanged)
659 _rows [i].RejectChanges ();
664 /// Resets the DataTable to its original state.
668 public virtual void Reset()
673 /// Gets an array of all DataRow objects.
677 public DataRow[] Select()
680 DataRow[] dataRows = {null};
685 /// Gets an array of all DataRow objects that match
686 /// the filter criteria in order of primary key (or
687 /// lacking one, order of addition.)
691 public DataRow[] Select(string filterExpression)
693 ExpressionElement Expression = new ExpressionMainElement (filterExpression);
695 ArrayList List = new ArrayList ();
696 foreach (DataRow Row in Rows) {
698 if (Expression.Test (Row))
702 return (DataRow [])List.ToArray (typeof (DataRow));
706 /// Gets an array of all DataRow objects that
707 /// match the filter criteria, in the the
708 /// specified sort order.
711 public DataRow[] Select(string filterExpression, string sort)
713 DataRow[] dataRows = {null};
718 /// Gets an array of all DataRow objects that match
719 /// the filter in the order of the sort, that match
720 /// the specified state.
723 public DataRow[] Select(string filterExpression, string sort, DataViewRowState recordStates)
725 DataRow[] dataRows = {null};
730 /// Gets the TableName and DisplayExpression, if
731 /// there is one as a concatenated string.
733 public override string ToString()
735 //LAMESPEC: spec says concat the two. impl puts a
736 //plus sign infront of DisplayExpression
737 return TableName + " " + DisplayExpression;
741 #region Events /////////////////
744 /// Raises the ColumnChanged event.
746 protected virtual void OnColumnChanged(DataColumnChangeEventArgs e)
748 if (null != ColumnChanged)
750 ColumnChanged(this, e);
755 /// Raises the ColumnChanging event.
757 protected virtual void OnColumnChanging(DataColumnChangeEventArgs e)
759 if (null != ColumnChanging)
761 ColumnChanging(this, e);
766 /// Raises the PropertyChanging event.
769 protected internal virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent)
771 // if (null != PropertyChanging)
773 // PropertyChanging(this, e);
778 /// Notifies the DataTable that a DataColumn is being removed.
781 protected internal virtual void OnRemoveColumn(DataColumn column)
783 // if (null != RemoveColumn)
785 // RemoveColumn(this, e);
790 /// Raises the RowChanged event.
793 protected virtual void OnRowChanged(DataRowChangeEventArgs e)
795 if (null != RowChanged)
803 /// Raises the RowChanging event.
806 protected virtual void OnRowChanging(DataRowChangeEventArgs e)
808 if (null != RowChanging)
810 RowChanging(this, e);
815 /// Raises the RowDeleted event.
817 protected virtual void OnRowDeleted(DataRowChangeEventArgs e)
819 if (null != RowDeleted)
826 /// Raises the RowDeleting event.
828 protected virtual void OnRowDeleting(DataRowChangeEventArgs e)
830 if (null != RowDeleting)
832 RowDeleting(this, e);
837 private DataColumn CopyColumn (DataColumn Column)
839 DataColumn Copy = new DataColumn ();
841 // Copy all the properties of column
842 Copy.AllowDBNull = Column.AllowDBNull;
843 Copy.AutoIncrement = Column.AutoIncrement;
844 Copy.AutoIncrementSeed = Column.AutoIncrementSeed;
845 Copy.AutoIncrementStep = Column.AutoIncrementStep;
846 Copy.Caption = Column.Caption;
847 Copy.ColumnMapping = Column.ColumnMapping;
848 Copy.ColumnName = Column.ColumnName;
852 Copy.Expression = Column.Expression;
853 //Copy.ExtendedProperties
854 Copy.MaxLength = Column.MaxLength;
855 Copy.Namespace = Column.Namespace;
856 Copy.Prefix = Column.Prefix;
857 Copy.ReadOnly = Column.ReadOnly;
859 Copy.Unique = Column.Unique;
865 /// Occurs when after a value has been changed for
866 /// the specified DataColumn in a DataRow.
868 [DataCategory ("Data")]
869 [DataSysDescription ("Occurs when a value has been changed for this column.")]
870 public event DataColumnChangeEventHandler ColumnChanged;
873 /// Occurs when a value is being changed for the specified
874 /// DataColumn in a DataRow.
876 [DataCategory ("Data")]
877 [DataSysDescription ("Occurs when a value has been submitted for this column. The user can modify the proposed value and should throw an exception to cancel the edit.")]
878 public event DataColumnChangeEventHandler ColumnChanging;
881 /// Occurs after a DataRow has been changed successfully.
883 [DataCategory ("Data")]
884 [DataSysDescription ("Occurs after a row in the table has been successfully edited.")]
885 public event DataRowChangeEventHandler RowChanged;
888 /// Occurs when a DataRow is changing.
890 [DataCategory ("Data")]
891 [DataSysDescription ("Occurs when the row is being changed so that the event handler can modify or cancel the change. The user can modify values in the row and should throw an exception to cancel the edit.")]
892 public event DataRowChangeEventHandler RowChanging;
895 /// Occurs after a row in the table has been deleted.
897 [DataCategory ("Data")]
898 [DataSysDescription ("Occurs after a row in the table has been successfully deleted.")]
899 public event DataRowChangeEventHandler RowDeleted;
902 /// Occurs before a row in the table is about to be deleted.
904 [DataCategory ("Data")]
905 [DataSysDescription ("Occurs when a row in the table marked for deletion. Throw an exception to cancel the deletion.")]
906 public event DataRowChangeEventHandler RowDeleting;