2 // System.Data.DataTable.cs
\r
5 // Franklin Wise <gracenote@earthlink.net>
\r
6 // Christopher Podurgiel (cpodurgiel@msn.com)
\r
7 // Daniel Morgan <danmorg@sc.rr.com>
\r
8 // Rodrigo Moya <rodrigo@ximian.com>
\r
9 // Tim Coleman (tim@timcoleman.com)
\r
10 // Ville Palo <vi64pa@koti.soon.fi>
\r
11 // Sureshkumar T <tsureshkumar@novell.com>
\r
12 // Konstantin Triger <kostat@mainsoft.com>
\r
14 // (C) Chris Podurgiel
\r
15 // (C) Ximian, Inc 2002
\r
16 // Copyright (C) Tim Coleman, 2002-2003
\r
17 // Copyright (C) Daniel Morgan, 2002-2003
\r
21 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
\r
23 // Permission is hereby granted, free of charge, to any person obtaining
\r
24 // a copy of this software and associated documentation files (the
\r
25 // "Software"), to deal in the Software without restriction, including
\r
26 // without limitation the rights to use, copy, modify, merge, publish,
\r
27 // distribute, sublicense, and/or sell copies of the Software, and to
\r
28 // permit persons to whom the Software is furnished to do so, subject to
\r
29 // the following conditions:
\r
31 // The above copyright notice and this permission notice shall be
\r
32 // included in all copies or substantial portions of the Software.
\r
34 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
35 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
36 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
37 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
38 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
39 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
40 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
44 using System.Data.Common;
\r
45 using System.Collections;
\r
47 using System.Collections.Generic;
\r
49 using System.ComponentModel;
\r
50 using System.Globalization;
\r
52 using System.Runtime.Serialization;
\r
54 using System.Xml.Schema;
\r
55 using System.Xml.Serialization;
\r
56 using System.Text.RegularExpressions;
\r
57 using Mono.Data.SqlExpressions;
\r
59 namespace System.Data {
\r
61 [ToolboxItem (false)]
\r
62 [DefaultEvent ("RowChanging")]
\r
63 [DefaultProperty ("TableName")]
\r
64 [DesignTimeVisible (false)]
\r
65 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DataTableEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
\r
67 public partial class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable {
\r
70 internal DataSet dataSet;
\r
72 private bool _caseSensitive;
\r
73 private DataColumnCollection _columnCollection;
\r
74 private ConstraintCollection _constraintCollection;
\r
75 // never access it. Use DefaultView.
\r
76 private DataView _defaultView = null;
\r
78 private string _displayExpression;
\r
79 private PropertyCollection _extendedProperties;
\r
80 private bool _hasErrors;
\r
81 private CultureInfo _locale;
\r
82 private int _minimumCapacity;
\r
83 private string _nameSpace;
\r
84 private DataRelationCollection _childRelations;
\r
85 private DataRelationCollection _parentRelations;
\r
86 private string _prefix;
\r
87 private UniqueConstraint _primaryKeyConstraint;
\r
88 private DataRowCollection _rows;
\r
89 private ISite _site;
\r
90 private string _tableName;
\r
91 private bool _containsListCollection;
\r
92 private string _encodedTableName;
\r
93 internal bool _duringDataLoad;
\r
94 internal bool _nullConstraintViolationDuringDataLoad;
\r
95 private bool dataSetPrevEnforceConstraints;
\r
96 private bool dataTablePrevEnforceConstraints;
\r
97 private bool enforceConstraints = true;
\r
98 private DataRowBuilder _rowBuilder;
\r
99 private ArrayList _indexes;
\r
100 private RecordCache _recordCache;
\r
101 private int _defaultValuesRowIndex = -1;
\r
102 protected internal bool fInitInProgress;
\r
104 // If CaseSensitive property is changed once it does not anymore follow owner DataSet's
\r
105 // CaseSensitive property. So when you lost you virginity it's gone for ever
\r
106 private bool _virginCaseSensitive = true;
\r
108 private PropertyDescriptorCollection _propertyDescriptorsCache;
\r
109 static DataColumn[] _emptyColumnArray = new DataColumn[0];
\r
111 // Regex to parse the Sort string.
\r
112 static Regex SortRegex = new Regex ( @"^((\[(?<ColName>.+)\])|(?<ColName>\S+))([ ]+(?<Order>ASC|DESC))?$",
\r
113 RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture);
\r
116 DataColumn [] _latestPrimaryKeyCols;
\r
117 #endregion //Fields
\r
120 /// Initializes a new instance of the DataTable class with no arguments.
\r
122 public DataTable ()
\r
125 _columnCollection = new DataColumnCollection(this);
\r
126 _constraintCollection = new ConstraintCollection(this);
\r
127 _extendedProperties = new PropertyCollection();
\r
130 _caseSensitive = false; //default value
\r
131 _displayExpression = null;
\r
132 _primaryKeyConstraint = null;
\r
134 _rows = new DataRowCollection (this);
\r
135 _indexes = new ArrayList();
\r
136 _recordCache = new RecordCache(this);
\r
138 //LAMESPEC: spec says 25 impl does 50
\r
139 _minimumCapacity = 50;
\r
141 _childRelations = new DataRelationCollection.DataTableRelationCollection (this);
\r
142 _parentRelations = new DataRelationCollection.DataTableRelationCollection (this);
\r
146 /// Intitalizes a new instance of the DataTable class with the specified table name.
\r
148 public DataTable (string tableName)
\r
151 _tableName = tableName;
\r
155 /// Initializes a new instance of the DataTable class with the SerializationInfo and the StreamingContext.
\r
157 protected DataTable (SerializationInfo info, StreamingContext context)
\r
161 SerializationInfoEnumerator e = info.GetEnumerator ();
\r
162 SerializationFormat serializationFormat = SerializationFormat.Xml;
\r
164 while (e.MoveNext()) {
\r
165 if (e.ObjectType == typeof(System.Data.SerializationFormat)) {
\r
166 serializationFormat = (SerializationFormat) e.Value;
\r
170 if (serializationFormat == SerializationFormat.Xml) {
\r
172 string schema = info.GetString ("XmlSchema");
\r
173 string data = info.GetString ("XmlDiffGram");
\r
175 DataSet ds = new DataSet ();
\r
176 ds.ReadXmlSchema (new StringReader (schema));
\r
177 ds.Tables [0].CopyProperties (this);
\r
178 ds = new DataSet ();
\r
179 ds.Tables.Add (this);
\r
180 ds.ReadXml (new StringReader (data), XmlReadMode.DiffGram);
\r
181 ds.Tables.Remove (this);
\r
182 /* keeping for a while. With the change above, we shouldn't have to consider
\r
183 * DataTable mode in schema inference/read.
\r
184 XmlSchemaMapper mapper = new XmlSchemaMapper (this);
\r
185 XmlTextReader xtr = new XmlTextReader(new StringReader (schema));
\r
188 XmlDiffLoader loader = new XmlDiffLoader (this);
\r
189 xtr = new XmlTextReader(new StringReader (data));
\r
193 } else /*if (Tables.RemotingFormat == SerializationFormat.Binary)*/ {
\r
194 BinaryDeserializeTable (info);
\r
200 /// Indicates whether string comparisons within the table are case-sensitive.
\r
203 [DataSysDescription ("Indicates whether comparing strings within the table is case sensitive.")]
\r
205 public bool CaseSensitive {
\r
207 if (_virginCaseSensitive && dataSet != null)
\r
208 return dataSet.CaseSensitive;
\r
210 return _caseSensitive;
\r
213 if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
\r
214 throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
\r
216 _virginCaseSensitive = false;
\r
217 _caseSensitive = value;
\r
218 ResetCaseSensitiveIndexes();
\r
222 internal ArrayList Indexes {
\r
223 get { return _indexes; }
\r
226 internal void ChangedDataColumn (DataRow dr, DataColumn dc, object pv)
\r
228 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
\r
229 OnColumnChanged (e);
\r
232 internal void ChangingDataColumn (DataRow dr, DataColumn dc, object pv)
\r
234 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
\r
235 OnColumnChanging (e);
\r
238 internal void DeletedDataRow (DataRow dr, DataRowAction action)
\r
240 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
244 internal void DeletingDataRow (DataRow dr, DataRowAction action)
\r
246 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
250 internal void ChangedDataRow (DataRow dr, DataRowAction action)
\r
252 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
256 internal void ChangingDataRow (DataRow dr, DataRowAction action)
\r
258 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
263 /// Gets the collection of child relations for this DataTable.
\r
265 [Browsable (false)]
\r
267 [DataSysDescription ("Returns the child relations for this table.")]
\r
269 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
270 public DataRelationCollection ChildRelations {
\r
271 get { return _childRelations; }
\r
275 /// Gets the collection of columns that belong to this table.
\r
277 [DataCategory ("Data")]
\r
279 [DataSysDescription ("The collection that holds the columns for this table.")]
\r
281 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
\r
282 public DataColumnCollection Columns {
\r
283 get { return _columnCollection; }
\r
287 /// Gets the collection of constraints maintained by this table.
\r
289 [DataCategory ("Data")]
\r
291 [DataSysDescription ("The collection that holds the constraints for this table.")]
\r
293 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
\r
294 public ConstraintCollection Constraints {
\r
295 get { return _constraintCollection; }
\r
297 internal set { _constraintCollection = value; }
\r
302 /// Gets the DataSet that this table belongs to.
\r
304 [Browsable (false)]
\r
306 [DataSysDescription ("Indicates the DataSet to which this table belongs.")]
\r
308 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
309 public DataSet DataSet {
\r
310 get { return dataSet; }
\r
314 /// Gets a customized view of the table which may
\r
315 /// include a filtered view, or a cursor position.
\r
317 [Browsable (false)]
\r
319 [DataSysDescription ("This is the default DataView for the table.")]
\r
321 public DataView DefaultView {
\r
323 if (_defaultView == null) {
\r
325 if (_defaultView == null){
\r
326 if (dataSet != null)
\r
327 _defaultView = dataSet.DefaultViewManager.CreateDataView(this);
\r
329 _defaultView = new DataView(this);
\r
333 return _defaultView;
\r
339 /// Gets or sets the expression that will return
\r
340 /// a value used to represent this table in the user interface.
\r
342 [DataCategory ("Data")]
\r
344 [DataSysDescription ("The expression used to compute the data-bound value of this row.")]
\r
346 [DefaultValue ("")]
\r
347 public string DisplayExpression {
\r
348 get { return _displayExpression == null ? "" : _displayExpression; }
\r
349 set { _displayExpression = value; }
\r
353 /// Gets the collection of customized user information.
\r
355 [Browsable (false)]
\r
356 [DataCategory ("Data")]
\r
358 [DataSysDescription ("The collection that holds custom user information.")]
\r
360 public PropertyCollection ExtendedProperties {
\r
361 get { return _extendedProperties; }
\r
365 /// Gets a value indicating whether there are errors in
\r
366 /// any of the_rows in any of the tables of the DataSet to
\r
367 /// which the table belongs.
\r
369 [Browsable (false)]
\r
371 [DataSysDescription ("Returns whether the table has errors.")]
\r
373 public bool HasErrors {
\r
375 // we can not use the _hasError flag because we do not know when to turn it off!
\r
376 for (int i = 0; i < _rows.Count; i++) {
\r
377 if (_rows[i].HasErrors)
\r
385 /// Gets or sets the locale information used to
\r
386 /// compare strings within the table.
\r
389 [DataSysDescription ("Indicates a locale under which to compare strings within the table.")]
\r
391 public CultureInfo Locale {
\r
393 // if the locale is null, we check for the DataSet locale
\r
394 // and if the DataSet is null we return the current culture.
\r
395 // this way if DataSet locale is changed, only if there is no locale for
\r
396 // the DataTable it influece the Locale get;
\r
397 if (_locale != null)
\r
399 if (DataSet != null)
\r
400 return DataSet.Locale;
\r
401 return CultureInfo.CurrentCulture;
\r
404 if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
\r
405 throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
\r
407 if (_locale == null || !_locale.Equals(value))
\r
412 internal bool LocaleSpecified {
\r
413 get { return _locale != null; }
\r
417 /// Gets or sets the initial starting size for this table.
\r
419 [DataCategory ("Data")]
\r
421 [DataSysDescription ("Indicates an initial starting size for this table.")]
\r
423 [DefaultValue (50)]
\r
424 public int MinimumCapacity {
\r
425 get { return _minimumCapacity; }
\r
426 set { _minimumCapacity = value; }
\r
430 /// Gets or sets the namespace for the XML represenation
\r
431 /// of the data stored in the DataTable.
\r
433 [DataCategory ("Data")]
\r
435 [DataSysDescription ("Indicates the XML uri namespace for the elements contained in this table.")]
\r
437 public string Namespace {
\r
439 if (_nameSpace != null)
\r
441 if (DataSet != null)
\r
442 return DataSet.Namespace;
\r
443 return String.Empty;
\r
445 set { _nameSpace = value; }
\r
449 /// Gets the collection of parent relations for
\r
450 /// this DataTable.
\r
452 [Browsable (false)]
\r
454 [DataSysDescription ("Returns the parent relations for this table.")]
\r
456 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
457 public DataRelationCollection ParentRelations {
\r
458 get { return _parentRelations; }
\r
462 /// Gets or sets the namespace for the XML represenation
\r
463 /// of the data stored in the DataTable.
\r
465 [DataCategory ("Data")]
\r
467 [DataSysDescription ("Indicates the Prefix of the namespace used for this table in XML representation.")]
\r
469 [DefaultValue ("")]
\r
470 public string Prefix {
\r
471 get { return _prefix == null ? "" : _prefix; }
\r
473 // Prefix cannot contain any special characters other than '_' and ':'
\r
474 for (int i = 0; i < value.Length; i++) {
\r
475 if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
\r
476 throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
\r
483 /// Gets or sets an array of columns that function as
\r
484 /// primary keys for the data table.
\r
486 [DataCategory ("Data")]
\r
488 [DataSysDescription ("Indicates the column(s) that represent the primary key for this table.")]
\r
490 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
\r
491 [TypeConverterAttribute ("System.Data.PrimaryKeyTypeConverter, " + Consts.AssemblySystem_Data)]
\r
492 public DataColumn[] PrimaryKey {
\r
494 if (_primaryKeyConstraint == null)
\r
495 return new DataColumn[] {};
\r
496 return _primaryKeyConstraint.Columns;
\r
499 if (value == null || value.Length == 0) {
\r
500 if (_primaryKeyConstraint != null) {
\r
501 _primaryKeyConstraint.SetIsPrimaryKey (false);
\r
502 Constraints.Remove(_primaryKeyConstraint);
\r
503 _primaryKeyConstraint = null;
\r
508 if (InitInProgress) {
\r
509 _latestPrimaryKeyCols = value;
\r
513 // first check if value is the same as current PK.
\r
514 if (_primaryKeyConstraint != null &&
\r
515 DataColumn.AreColumnSetsTheSame (value, _primaryKeyConstraint.Columns))
\r
518 //Does constraint exist for these columns
\r
519 UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet (this.Constraints, (DataColumn[]) value);
\r
521 //if constraint doesn't exist for columns
\r
522 //create new unique primary key constraint
\r
524 foreach (DataColumn Col in (DataColumn []) value) {
\r
525 if (Col.Table == null)
\r
528 if (Columns.IndexOf (Col) < 0)
\r
529 throw new ArgumentException ("PrimaryKey columns do not belong to this table.");
\r
531 // create constraint with primary key indication set to false
\r
532 // to avoid recursion
\r
533 uc = new UniqueConstraint ((DataColumn []) value, false);
\r
534 Constraints.Add (uc);
\r
537 //Remove the existing primary key
\r
538 if (_primaryKeyConstraint != null) {
\r
539 _primaryKeyConstraint.SetIsPrimaryKey (false);
\r
540 Constraints.Remove (_primaryKeyConstraint);
\r
541 _primaryKeyConstraint = null;
\r
544 //set the constraint as the new primary key
\r
545 UniqueConstraint.SetAsPrimaryKey (Constraints, uc);
\r
546 _primaryKeyConstraint = uc;
\r
548 for (int j = 0; j < uc.Columns.Length; ++j)
\r
549 uc.Columns [j].AllowDBNull = false;
\r
553 internal UniqueConstraint PrimaryKeyConstraint {
\r
554 get { return _primaryKeyConstraint; }
\r
558 /// Gets the collection of_rows that belong to this table.
\r
560 [Browsable (false)]
\r
562 [DataSysDescription ("Indicates the collection that holds the rows of data for this table.")]
\r
564 public DataRowCollection Rows {
\r
565 get { return _rows; }
\r
569 /// Gets or sets an System.ComponentModel.ISite
\r
570 /// for the DataTable.
\r
572 [Browsable (false)]
\r
573 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
574 public override ISite Site {
\r
575 get { return _site; }
\r
576 set { _site = value; }
\r
580 /// Gets or sets the name of the the DataTable.
\r
582 [DataCategory ("Data")]
\r
584 [DataSysDescription ("Indicates the name used to look up this table in the Tables collection of a DataSet.")]
\r
586 [DefaultValue ("")]
\r
587 [RefreshProperties (RefreshProperties.All)]
\r
588 public string TableName {
\r
589 get { return _tableName == null ? "" : _tableName; }
\r
590 set { _tableName = value; }
\r
593 bool IListSource.ContainsListCollection {
\r
594 // the collection is a DataView
\r
595 get { return false; }
\r
598 internal RecordCache RecordCache {
\r
599 get { return _recordCache; }
\r
602 private DataRowBuilder RowBuilder {
\r
604 // initiate only one row builder.
\r
605 if (_rowBuilder == null)
\r
606 _rowBuilder = new DataRowBuilder (this, -1, 0);
\r
608 // new row get id -1.
\r
609 _rowBuilder._rowId = -1;
\r
611 return _rowBuilder;
\r
615 internal bool EnforceConstraints {
\r
616 get { return enforceConstraints; }
\r
618 if (value == enforceConstraints)
\r
622 // reset indexes since they may be outdated
\r
625 // assert all constraints
\r
626 foreach (Constraint constraint in Constraints)
\r
627 constraint.AssertConstraint ();
\r
629 AssertNotNullConstraints ();
\r
632 Constraint.ThrowConstraintException ();
\r
634 enforceConstraints = value;
\r
638 internal void AssertNotNullConstraints ()
\r
640 if (_duringDataLoad && !_nullConstraintViolationDuringDataLoad)
\r
644 for (int i = 0; i < Columns.Count; i++) {
\r
645 DataColumn column = Columns [i];
\r
646 if (column.AllowDBNull)
\r
648 for (int j = 0; j < Rows.Count; j++) {
\r
649 if (Rows [j].HasVersion (DataRowVersion.Default) && Rows[j].IsNull (column)) {
\r
651 string errMsg = String.Format ("Column '{0}' does not allow DBNull.Value.",
\r
652 column.ColumnName);
\r
653 Rows [j].SetColumnError (i, errMsg);
\r
654 Rows [j].RowError = errMsg;
\r
658 _nullConstraintViolationDuringDataLoad = seen;
\r
661 internal bool RowsExist (DataColumn [] columns, DataColumn [] relatedColumns, DataRow row)
\r
663 int curIndex = row.IndexFromVersion (DataRowVersion.Default);
\r
664 int tmpRecord = RecordCache.NewRecord ();
\r
667 for (int i = 0; i < relatedColumns.Length; i++)
\r
668 // according to MSDN: the DataType value for both columns must be identical.
\r
669 columns [i].DataContainer.CopyValue (relatedColumns [i].DataContainer, curIndex, tmpRecord);
\r
670 return RowsExist (columns, tmpRecord);
\r
672 RecordCache.DisposeRecord (tmpRecord);
\r
676 bool RowsExist (DataColumn [] columns, int index)
\r
678 Index indx = this.FindIndex (columns);
\r
681 return indx.Find (index) != -1;
\r
683 // we have to perform full-table scan
\r
684 // check that there is a parent for this row.
\r
685 foreach (DataRow thisRow in this.Rows) {
\r
686 if (thisRow.RowState == DataRowState.Deleted)
\r
688 // check if the values in the columns are equal
\r
689 int thisIndex = thisRow.IndexFromVersion (
\r
690 thisRow.RowState == DataRowState.Modified ? DataRowVersion.Original : DataRowVersion.Current);
\r
692 foreach (DataColumn column in columns) {
\r
693 if (column.DataContainer.CompareValues (thisIndex, index) != 0) {
\r
705 /// Commits all the changes made to this table since the
\r
706 /// last time AcceptChanges was called.
\r
708 public void AcceptChanges ()
\r
710 //FIXME: Do we need to validate anything here or
\r
711 //try to catch any errors to deal with them?
\r
713 // we do not use foreach because if one of the rows is in Delete state
\r
714 // it will be romeved from Rows and we get an exception.
\r
716 for (int i = 0; i < Rows.Count; ) {
\r
718 myRow.AcceptChanges ();
\r
720 // if the row state is Detached it meens that it was removed from row list (Rows)
\r
721 // so we should not increase 'i'.
\r
722 if (myRow.RowState != DataRowState.Detached)
\r
725 _rows.OnListChanged (this, new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
729 /// Begins the initialization of a DataTable that is used
\r
730 /// on a form or used by another component. The initialization
\r
731 /// occurs at runtime.
\r
739 InitInProgress = true;
\r
741 tableInitialized = false;
\r
746 /// Turns off notifications, index maintenance, and
\r
747 /// constraints while loading data.
\r
749 public void BeginLoadData ()
\r
751 if (this._duringDataLoad)
\r
754 //duringDataLoad is important to EndLoadData and
\r
755 //for not throwing unexpected exceptions.
\r
756 this._duringDataLoad = true;
\r
757 this._nullConstraintViolationDuringDataLoad = false;
\r
759 if (this.dataSet != null) {
\r
760 //Saving old Enforce constraints state for later
\r
761 //use in the EndLoadData.
\r
762 this.dataSetPrevEnforceConstraints = this.dataSet.EnforceConstraints;
\r
763 this.dataSet.EnforceConstraints = false;
\r
765 //if table does not belong to any data set use EnforceConstraints of the table
\r
766 this.EnforceConstraints = false;
\r
772 /// Clears the DataTable of all data.
\r
774 public void Clear ()
\r
776 DataTableClearing ();
\r
777 // Foriegn key constraints are checked in _rows.Clear method
\r
779 foreach (Index index in Indexes)
\r
781 DataTableCleared ();
\r
784 // defined in the NET_2_0 profile
\r
785 partial void DataTableClearing ();
\r
786 partial void DataTableCleared ();
\r
789 /// Clones the structure of the DataTable, including
\r
790 /// all DataTable schemas and constraints.
\r
792 public virtual DataTable Clone ()
\r
794 // Use Activator so we can use non-public constructors.
\r
795 DataTable Copy = (DataTable) Activator.CreateInstance (GetType (), true);
\r
796 CopyProperties (Copy);
\r
801 /// Computes the given expression on the current_rows that
\r
802 /// pass the filter criteria.
\r
804 public object Compute (string expression, string filter)
\r
806 // expression is an aggregate function
\r
807 // filter is an expression used to limit rows
\r
809 DataRow [] rows = Select (filter);
\r
811 if (rows == null || rows.Length == 0)
\r
812 return DBNull.Value;
\r
814 Parser parser = new Parser (rows);
\r
815 IExpression expr = parser.Compile (expression);
\r
816 object obj = expr.Eval (rows [0]);
\r
822 /// Copies both the structure and data for this DataTable.
\r
824 public DataTable Copy ()
\r
826 DataTable copy = Clone ();
\r
828 copy._duringDataLoad = true;
\r
829 foreach (DataRow row in Rows) {
\r
830 DataRow newRow = copy.NewNotInitializedRow ();
\r
831 copy.Rows.AddInternal (newRow);
\r
832 CopyRow (row, newRow);
\r
834 copy._duringDataLoad = false;
\r
836 // rebuild copy indexes after loading all rows
\r
837 copy.ResetIndexes ();
\r
841 internal void CopyRow (DataRow fromRow, DataRow toRow)
\r
843 if (fromRow.HasErrors)
\r
844 fromRow.CopyErrors (toRow);
\r
846 if (fromRow.HasVersion (DataRowVersion.Original))
\r
847 toRow.Original = toRow.Table.RecordCache.CopyRecord (this, fromRow.Original, -1);
\r
849 if (fromRow.HasVersion (DataRowVersion.Current)) {
\r
850 if (fromRow.Original != fromRow.Current)
\r
851 toRow.Current = toRow.Table.RecordCache.CopyRecord (this, fromRow.Current, -1);
\r
853 toRow.Current = toRow.Original;
\r
857 private void CopyProperties (DataTable Copy)
\r
859 Copy.CaseSensitive = CaseSensitive;
\r
860 Copy._virginCaseSensitive = _virginCaseSensitive;
\r
862 // Copy.ChildRelations
\r
863 // Copy.Constraints
\r
865 // Copy.DefaultView
\r
867 Copy.DisplayExpression = DisplayExpression;
\r
868 if (ExtendedProperties.Count > 0) {
\r
869 // Cannot copy extended properties directly as the property does not have a set accessor
\r
870 Array tgtArray = Array.CreateInstance (typeof (object), ExtendedProperties.Count);
\r
871 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
\r
872 for (int i=0; i < ExtendedProperties.Count; i++)
\r
873 Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
\r
875 Copy._locale = _locale;
\r
876 Copy.MinimumCapacity = MinimumCapacity;
\r
877 Copy.Namespace = Namespace;
\r
878 // Copy.ParentRelations
\r
879 Copy.Prefix = Prefix;
\r
881 Copy.TableName = TableName;
\r
883 bool isEmpty = Copy.Columns.Count == 0;
\r
886 foreach (DataColumn column in Columns) {
\r
887 // When cloning a table, the columns may be added in the default constructor.
\r
888 if (isEmpty || !Copy.Columns.Contains (column.ColumnName))
\r
889 Copy.Columns.Add (column.Clone ());
\r
892 CopyConstraints (Copy);
\r
893 // add primary key to the copy
\r
894 if (PrimaryKey.Length > 0) {
\r
895 DataColumn[] pColumns = new DataColumn[PrimaryKey.Length];
\r
896 for (int i = 0; i < pColumns.Length; i++)
\r
897 pColumns[i] = Copy.Columns[PrimaryKey[i].ColumnName];
\r
899 Copy.PrimaryKey = pColumns;
\r
903 private void CopyConstraints (DataTable copy)
\r
905 UniqueConstraint origUc;
\r
906 UniqueConstraint copyUc;
\r
907 for (int i = 0; i < this.Constraints.Count; i++) {
\r
908 if (this.Constraints[i] is UniqueConstraint) {
\r
909 // typed ds can already contain the constraints
\r
910 if (copy.Constraints.Contains (this.Constraints [i].ConstraintName))
\r
913 origUc = (UniqueConstraint) this.Constraints [i];
\r
914 DataColumn [] columns = new DataColumn [origUc.Columns.Length];
\r
915 for (int j = 0; j < columns.Length; j++)
\r
916 columns[j] = copy.Columns [origUc.Columns [j].ColumnName];
\r
918 copyUc = new UniqueConstraint (origUc.ConstraintName, columns, origUc.IsPrimaryKey);
\r
919 copy.Constraints.Add (copyUc);
\r
924 /// Ends the initialization of a DataTable that is used
\r
925 /// on a form or used by another component. The
\r
926 /// initialization occurs at runtime.
\r
934 InitInProgress = false;
\r
935 DataTableInitialized ();
\r
939 // defined in NET_2_0 profile
\r
940 partial void DataTableInitialized ();
\r
942 internal bool InitInProgress {
\r
943 get { return fInitInProgress; }
\r
944 set { fInitInProgress = value; }
\r
947 internal void FinishInit ()
\r
949 UniqueConstraint oldPK = _primaryKeyConstraint;
\r
951 // Columns shud be added 'before' the constraints
\r
952 Columns.PostAddRange ();
\r
954 // Add the constraints
\r
955 _constraintCollection.PostAddRange ();
\r
957 // ms.net behavior : If a PrimaryKey (UniqueConstraint) is added thru AddRange,
\r
958 // then it takes precedence over an direct assignment of PrimaryKey
\r
959 if (_primaryKeyConstraint == oldPK)
\r
960 PrimaryKey = _latestPrimaryKeyCols;
\r
964 /// Turns on notifications, index maintenance, and
\r
965 /// constraints after loading data.
\r
967 public void EndLoadData ()
\r
969 if (this._duringDataLoad) {
\r
970 //Getting back to previous EnforceConstraint state
\r
971 if (this.dataSet != null)
\r
972 this.dataSet.InternalEnforceConstraints (this.dataSetPrevEnforceConstraints, true);
\r
974 this.EnforceConstraints = true;
\r
976 this._duringDataLoad = false;
\r
981 /// Gets a copy of the DataTable that contains all
\r
982 /// changes made to it since it was loaded or
\r
983 /// AcceptChanges was last called.
\r
985 public DataTable GetChanges ()
\r
987 return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
\r
991 /// Gets a copy of the DataTable containing all
\r
992 /// changes made to it since it was last loaded, or
\r
993 /// since AcceptChanges was called, filtered by DataRowState.
\r
995 public DataTable GetChanges (DataRowState rowStates)
\r
997 DataTable copyTable = null;
\r
999 foreach (DataRow row in Rows) {
\r
1000 // The spec says relationship constraints may cause Unchanged parent rows to be included but
\r
1001 // MS .NET 1.1 does not include Unchanged rows even if their child rows are changed.
\r
1002 if (!row.IsRowChanged (rowStates))
\r
1004 if (copyTable == null)
\r
1005 copyTable = Clone ();
\r
1006 DataRow newRow = copyTable.NewNotInitializedRow ();
\r
1007 row.CopyValuesToRow (newRow);
\r
1009 newRow.XmlRowID = row.XmlRowID;
\r
1011 copyTable.Rows.AddInternal (newRow);
\r
1018 /// Gets an array of DataRow objects that contain errors.
\r
1020 public DataRow [] GetErrors ()
\r
1022 ArrayList errors = new ArrayList();
\r
1023 for (int i = 0; i < _rows.Count; i++) {
\r
1024 if (_rows[i].HasErrors)
\r
1025 errors.Add (_rows[i]);
\r
1028 DataRow[] ret = NewRowArray (errors.Count);
\r
1029 errors.CopyTo (ret, 0);
\r
1034 /// This member is only meant to support Mono's infrastructure
\r
1036 protected virtual DataTable CreateInstance ()
\r
1038 return Activator.CreateInstance (this.GetType (), true) as DataTable;
\r
1042 /// This member is only meant to support Mono's infrastructure
\r
1044 protected virtual Type GetRowType ()
\r
1046 return typeof (DataRow);
\r
1050 /// This member is only meant to support Mono's infrastructure
\r
1052 /// Used for Data Binding between System.Web.UI. controls
\r
1053 /// like a DataGrid
\r
1055 /// System.Windows.Forms controls like a DataGrid
\r
1057 IList IListSource.GetList ()
\r
1059 IList list = (IList) DefaultView;
\r
1064 /// Copies a DataRow into a DataTable, preserving any
\r
1065 /// property settings, as well as original and current values.
\r
1067 public void ImportRow (DataRow row)
\r
1069 if (row.RowState == DataRowState.Detached)
\r
1072 DataRow newRow = NewNotInitializedRow ();
\r
1074 int original = -1;
\r
1075 if (row.HasVersion (DataRowVersion.Original)) {
\r
1076 original = row.IndexFromVersion (DataRowVersion.Original);
\r
1077 newRow.Original = RecordCache.NewRecord ();
\r
1078 RecordCache.CopyRecord (row.Table, original, newRow.Original);
\r
1081 if (row.HasVersion (DataRowVersion.Current)) {
\r
1082 int current = row.IndexFromVersion (DataRowVersion.Current);
\r
1083 if (current == original) {
\r
1084 newRow.Current = newRow.Original;
\r
1086 newRow.Current = RecordCache.NewRecord ();
\r
1087 RecordCache.CopyRecord (row.Table, current, newRow.Current);
\r
1091 //Import the row only if RowState is not detached
\r
1092 //Validation for Deleted Rows happens during Accept/RejectChanges
\r
1093 if (row.RowState != DataRowState.Deleted)
\r
1094 newRow.Validate ();
\r
1096 AddRowToIndexes (newRow);
\r
1097 Rows.AddInternal(newRow);
\r
1099 if (row.HasErrors)
\r
1100 row.CopyErrors (newRow);
\r
1103 internal int DefaultValuesRowIndex {
\r
1104 get { return _defaultValuesRowIndex; }
\r
1108 /// This member is only meant to support Mono's infrastructure
\r
1117 GetObjectData (SerializationInfo info, StreamingContext context)
\r
1120 if (RemotingFormat == SerializationFormat.Xml) {
\r
1123 if (dataSet != null)
\r
1126 dset = new DataSet ("tmpDataSet");
\r
1127 dset.Tables.Add (this);
\r
1130 StringWriter sw = new StringWriter ();
\r
1131 XmlTextWriter tw = new XmlTextWriter (sw);
\r
1132 tw.Formatting = Formatting.Indented;
\r
1133 dset.WriteIndividualTableContent (tw, this, XmlWriteMode.DiffGram);
\r
1136 StringWriter sw2 = new StringWriter ();
\r
1137 DataTableCollection tables = new DataTableCollection (dset);
\r
1138 tables.Add (this);
\r
1139 XmlSchemaWriter.WriteXmlSchema (dset, new XmlTextWriter (sw2), tables, null);
\r
1142 info.AddValue ("XmlSchema", sw2.ToString(), typeof(string));
\r
1143 info.AddValue ("XmlDiffGram", sw.ToString(), typeof(string));
\r
1145 } else /*if (RemotingFormat == SerializationFormat.Binary)*/ {
\r
1146 BinarySerializeProperty (info);
\r
1147 if (dataSet == null) {
\r
1148 for (int i = 0; i < Columns.Count; i++) {
\r
1149 info.AddValue ("DataTable.DataColumn_" + i + ".Expression",
\r
1150 Columns[i].Expression);
\r
1152 BinarySerialize (info, "DataTable_0.");
\r
1159 /// Finds and updates a specific row. If no matching row
\r
1160 /// is found, a new row is created using the given values.
\r
1162 public DataRow LoadDataRow (object [] values, bool fAcceptChanges)
\r
1164 DataRow row = null;
\r
1165 if (PrimaryKey.Length == 0) {
\r
1166 row = Rows.Add (values);
\r
1168 EnsureDefaultValueRowIndex ();
\r
1169 int newRecord = CreateRecord (values);
\r
1170 int existingRecord = _primaryKeyConstraint.Index.Find (newRecord);
\r
1172 if (existingRecord < 0) {
\r
1173 row = NewRowFromBuilder (RowBuilder);
\r
1174 row.Proposed = newRecord;
\r
1175 Rows.AddInternal(row);
\r
1176 if (!_duringDataLoad)
\r
1177 AddRowToIndexes (row);
\r
1179 row = RecordCache [existingRecord];
\r
1181 row.ImportRecord (newRecord);
\r
1186 if (fAcceptChanges)
\r
1187 row.AcceptChanges ();
\r
1192 internal DataRow LoadDataRow (IDataRecord record, int[] mapping, int length, bool fAcceptChanges)
\r
1194 DataRow row = null;
\r
1195 int tmpRecord = this.RecordCache.NewRecord ();
\r
1197 RecordCache.ReadIDataRecord (tmpRecord,record,mapping,length);
\r
1198 if (PrimaryKey.Length != 0) {
\r
1199 bool hasPrimaryValues = true;
\r
1200 foreach(DataColumn col in PrimaryKey) {
\r
1201 if(!(col.Ordinal < mapping.Length)) {
\r
1202 hasPrimaryValues = false;
\r
1207 if (hasPrimaryValues) {
\r
1208 int existingRecord = _primaryKeyConstraint.Index.Find (tmpRecord);
\r
1209 if (existingRecord != -1)
\r
1210 row = RecordCache [existingRecord];
\r
1214 if (row == null) {
\r
1215 row = NewNotInitializedRow ();
\r
1216 row.Proposed = tmpRecord;
\r
1217 Rows.AddInternal (row);
\r
1220 row.ImportRecord (tmpRecord);
\r
1224 if (fAcceptChanges)
\r
1225 row.AcceptChanges ();
\r
1228 this.RecordCache.DisposeRecord (tmpRecord);
\r
1235 /// Creates a new DataRow with the same schema as the table.
\r
1237 public DataRow NewRow ()
\r
1239 EnsureDefaultValueRowIndex();
\r
1241 DataRow newRow = NewRowFromBuilder (RowBuilder);
\r
1242 newRow.Proposed = CreateRecord (null);
\r
1243 NewRowAdded (newRow);
\r
1247 // defined in the NET_2_0 profile
\r
1248 partial void NewRowAdded (DataRow dr);
\r
1250 internal int CreateRecord (object [] values)
\r
1252 int valCount = values != null ? values.Length : 0;
\r
1253 if (valCount > Columns.Count)
\r
1254 throw new ArgumentException ("Input array is longer than the number of columns in this table.");
\r
1256 int index = RecordCache.NewRecord ();
\r
1259 for (int i = 0; i < valCount; i++) {
\r
1260 object value = values[i];
\r
1261 if (value == null)
\r
1262 Columns [i].SetDefaultValue (index);
\r
1264 Columns [i][index] = values [i];
\r
1267 for(int i = valCount; i < Columns.Count; i++)
\r
1268 Columns [i].SetDefaultValue (index);
\r
1272 RecordCache.DisposeRecord (index);
\r
1277 private void EnsureDefaultValueRowIndex ()
\r
1279 // initialize default values row for the first time
\r
1280 if (_defaultValuesRowIndex == -1) {
\r
1281 _defaultValuesRowIndex = RecordCache.NewRecord();
\r
1282 for (int i = 0; i < Columns.Count; ++i) {
\r
1283 DataColumn column = Columns [i];
\r
1284 column.DataContainer [_defaultValuesRowIndex] = column.DefaultValue;
\r
1290 /// This member supports the .NET Framework infrastructure
\r
1291 /// and is not intended to be used directly from your code.
\r
1293 DataRow [] empty_rows;
\r
1294 protected internal DataRow [] NewRowArray (int size)
\r
1296 if (size == 0 && empty_rows != null)
\r
1297 return empty_rows;
\r
1298 Type t = GetRowType ();
\r
1299 /* Avoid reflection if possible */
\r
1300 DataRow [] rows = t == typeof (DataRow) ? new DataRow [size] : (DataRow []) Array.CreateInstance (t, size);
\r
1302 empty_rows = rows;
\r
1307 /// Creates a new row from an existing row.
\r
1309 protected virtual DataRow NewRowFromBuilder (DataRowBuilder builder)
\r
1311 return new DataRow (builder);
\r
1314 internal DataRow NewNotInitializedRow ()
\r
1316 EnsureDefaultValueRowIndex ();
\r
1318 return NewRowFromBuilder (RowBuilder);
\r
1322 /// Rolls back all changes that have been made to the
\r
1323 /// table since it was loaded, or the last time AcceptChanges
\r
1326 public void RejectChanges ()
\r
1328 for (int i = _rows.Count - 1; i >= 0; i--) {
\r
1329 DataRow row = _rows [i];
\r
1330 if (row.RowState != DataRowState.Unchanged)
\r
1331 _rows [i].RejectChanges ();
\r
1336 /// Resets the DataTable to its original state.
\r
1338 public virtual void Reset ()
\r
1341 while (ParentRelations.Count > 0) {
\r
1342 if (dataSet.Relations.Contains (ParentRelations [ParentRelations.Count - 1].RelationName))
\r
1343 dataSet.Relations.Remove (ParentRelations [ParentRelations.Count - 1]);
\r
1346 while (ChildRelations.Count > 0) {
\r
1347 if (dataSet.Relations.Contains (ChildRelations [ChildRelations.Count - 1].RelationName))
\r
1348 dataSet.Relations.Remove (ChildRelations [ChildRelations.Count - 1]);
\r
1350 Constraints.Clear ();
\r
1355 /// Gets an array of all DataRow objects.
\r
1357 public DataRow[] Select ()
\r
1359 return Select (String.Empty, String.Empty, DataViewRowState.CurrentRows);
\r
1363 /// Gets an array of all DataRow objects that match
\r
1364 /// the filter criteria in order of primary key (or
\r
1365 /// lacking one, order of addition.)
\r
1367 public DataRow[] Select (string filterExpression)
\r
1369 return Select (filterExpression, String.Empty, DataViewRowState.CurrentRows);
\r
1373 /// Gets an array of all DataRow objects that
\r
1374 /// match the filter criteria, in the the
\r
1375 /// specified sort order.
\r
1377 public DataRow[] Select (string filterExpression, string sort)
\r
1379 return Select (filterExpression, sort, DataViewRowState.CurrentRows);
\r
1383 /// Gets an array of all DataRow objects that match
\r
1384 /// the filter in the order of the sort, that match
\r
1385 /// the specified state.
\r
1387 public DataRow [] Select (string filterExpression, string sort, DataViewRowState recordStates)
\r
1389 if (filterExpression == null)
\r
1390 filterExpression = String.Empty;
\r
1392 IExpression filter = null;
\r
1393 if (filterExpression != String.Empty) {
\r
1394 Parser parser = new Parser ();
\r
1395 filter = parser.Compile (filterExpression);
\r
1398 DataColumn [] columns = _emptyColumnArray;
\r
1399 ListSortDirection [] sorts = null;
\r
1401 if (sort != null && !sort.Equals(String.Empty))
\r
1402 columns = ParseSortString (this, sort, out sorts, false);
\r
1404 if (Rows.Count == 0)
\r
1405 return NewRowArray (0);
\r
1407 //if sort order is not given, sort it in Ascending order of the
\r
1408 //columns involved in the filter
\r
1409 if (columns.Length == 0 && filter != null) {
\r
1410 ArrayList list = new ArrayList ();
\r
1411 for (int i = 0; i < Columns.Count; ++i) {
\r
1412 if (!filter.DependsOn (Columns [i]))
\r
1414 list.Add (Columns [i]);
\r
1416 columns = (DataColumn []) list.ToArray (typeof (DataColumn));
\r
1419 bool addIndex = true;
\r
1420 if (filterExpression != String.Empty)
\r
1422 Index index = GetIndex (columns, sorts, recordStates, filter, false, addIndex);
\r
1424 int [] records = index.GetAll ();
\r
1425 DataRow [] dataRows = NewRowArray (index.Size);
\r
1426 for (int i = 0; i < dataRows.Length; i++)
\r
1427 dataRows [i] = RecordCache [records [i]];
\r
1432 private void AddIndex (Index index)
\r
1434 if (_indexes == null)
\r
1435 _indexes = new ArrayList();
\r
1436 _indexes.Add (index);
\r
1440 /// Returns index corresponding to columns,sort,row state filter and unique values given.
\r
1441 /// If such an index not exists, creates a new one.
\r
1443 /// <param name="columns">Columns set of the index to look for.</param>
\r
1444 /// <param name="sort">Columns sort order of the index to look for.</param>
\r
1445 /// <param name="rowState">Rpw state filter of the index to look for.</param>
\r
1446 /// <param name="unique">Uniqueness of the index to look for.</param>
\r
1447 /// <param name="strict">Indicates whenever the index found should correspond in its uniquness to the value of unique parameter specified.</param>
\r
1448 /// <param name="reset">Indicates whenever the already existing index should be forced to reset.</param>
\r
1449 /// <returns></returns>
\r
1450 internal Index GetIndex (DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter, bool reset)
\r
1452 return GetIndex (columns, sort, rowState, filter, reset, true);
\r
1455 internal Index GetIndex (DataColumn[] columns, ListSortDirection[] sort,
\r
1456 DataViewRowState rowState, IExpression filter,
\r
1457 bool reset, bool addIndex)
\r
1459 Index index = FindIndex(columns, sort, rowState, filter);
\r
1460 if (index == null) {
\r
1461 index = new Index(new Key (this, columns, sort, rowState, filter));
\r
1465 } else if (reset) {
\r
1466 // reset existing index only if asked for this
\r
1472 internal Index FindIndex (DataColumn[] columns)
\r
1474 return FindIndex (columns, null, DataViewRowState.None, null);
\r
1477 internal Index FindIndex (DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter)
\r
1479 if (Indexes != null) {
\r
1480 foreach (Index index in Indexes) {
\r
1481 if (index.Key.Equals (columns,sort,rowState, filter))
\r
1488 internal void ResetIndexes ()
\r
1490 foreach(Index index in Indexes)
\r
1494 internal void ResetCaseSensitiveIndexes ()
\r
1496 foreach (Index index in Indexes) {
\r
1497 bool containsStringcolumns = false;
\r
1498 foreach(DataColumn column in index.Key.Columns) {
\r
1499 if (column.DataType == typeof(string)) {
\r
1500 containsStringcolumns = true;
\r
1505 if (!containsStringcolumns && index.Key.HasFilter) {
\r
1506 foreach (DataColumn column in Columns) {
\r
1507 if ((column.DataType == DbTypes.TypeOfString) && (index.Key.DependsOn (column))) {
\r
1508 containsStringcolumns = true;
\r
1514 if (containsStringcolumns)
\r
1519 internal void DropIndex (Index index)
\r
1521 if (index != null && index.RefCount == 0) {
\r
1522 _indexes.Remove (index);
\r
1526 internal void DropReferencedIndexes (DataColumn column)
\r
1528 if (_indexes != null)
\r
1529 for (int i = _indexes.Count - 1; i >= 0; i--) {
\r
1530 Index indx = (Index)_indexes [i];
\r
1531 if (indx.Key.DependsOn (column))
\r
1532 _indexes.Remove (indx);
\r
1536 internal void AddRowToIndexes (DataRow row)
\r
1538 if (_indexes != null) {
\r
1539 for (int i = 0; i < _indexes.Count; ++i)
\r
1540 ((Index)_indexes [i]).Add (row);
\r
1544 internal void DeleteRowFromIndexes (DataRow row)
\r
1546 if (_indexes != null) {
\r
1547 foreach (Index indx in _indexes)
\r
1548 indx.Delete (row);
\r
1553 /// Gets the TableName and DisplayExpression, if
\r
1554 /// there is one as a concatenated string.
\r
1556 public override string ToString ()
\r
1558 //LAMESPEC: spec says concat the two. impl puts a
\r
1559 //plus sign infront of DisplayExpression
\r
1560 string retVal = TableName;
\r
1561 if(DisplayExpression != null && DisplayExpression != "")
\r
1562 retVal += " + " + DisplayExpression;
\r
1569 /// Raises the ColumnChanged event.
\r
1571 protected virtual void OnColumnChanged (DataColumnChangeEventArgs e)
\r
1573 if (null != ColumnChanged)
\r
1574 ColumnChanged (this, e);
\r
1577 internal void RaiseOnColumnChanged (DataColumnChangeEventArgs e)
\r
1579 OnColumnChanged (e);
\r
1583 /// Raises the ColumnChanging event.
\r
1585 protected virtual void OnColumnChanging (DataColumnChangeEventArgs e)
\r
1587 if (null != ColumnChanging)
\r
1588 ColumnChanging (this, e);
\r
1591 internal void RaiseOnColumnChanging (DataColumnChangeEventArgs e)
\r
1593 OnColumnChanging(e);
\r
1597 /// Raises the PropertyChanging event.
\r
1600 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
\r
1602 //if (null != PropertyChanging)
\r
1604 // PropertyChanging (this, pcevent);
\r
1606 throw new NotImplementedException ();
\r
1610 /// Notifies the DataTable that a DataColumn is being removed.
\r
1612 protected internal virtual void OnRemoveColumn (DataColumn column)
\r
1614 DropReferencedIndexes (column);
\r
1618 /// Raises the RowChanged event.
\r
1620 protected virtual void OnRowChanged (DataRowChangeEventArgs e)
\r
1622 if (null != RowChanged)
\r
1623 RowChanged (this, e);
\r
1628 /// Raises the RowChanging event.
\r
1630 protected virtual void OnRowChanging (DataRowChangeEventArgs e)
\r
1632 if (null != RowChanging)
\r
1633 RowChanging (this, e);
\r
1637 /// Raises the RowDeleted event.
\r
1639 protected virtual void OnRowDeleted (DataRowChangeEventArgs e)
\r
1641 if (null != RowDeleted)
\r
1642 RowDeleted (this, e);
\r
1646 /// Raises the RowDeleting event.
\r
1648 protected virtual void OnRowDeleting (DataRowChangeEventArgs e)
\r
1650 if (null != RowDeleting)
\r
1651 RowDeleting (this, e);
\r
1655 /// Occurs when after a value has been changed for
\r
1656 /// the specified DataColumn in a DataRow.
\r
1658 [DataCategory ("Data")]
\r
1660 [DataSysDescription ("Occurs when a value has been changed for this column.")]
\r
1662 public event DataColumnChangeEventHandler ColumnChanged;
\r
1665 /// Occurs when a value is being changed for the specified
\r
1666 /// DataColumn in a DataRow.
\r
1668 [DataCategory ("Data")]
\r
1670 [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.")]
\r
1672 public event DataColumnChangeEventHandler ColumnChanging;
\r
1675 /// Occurs after a DataRow has been changed successfully.
\r
1677 [DataCategory ("Data")]
\r
1679 [DataSysDescription ("Occurs after a row in the table has been successfully edited.")]
\r
1681 public event DataRowChangeEventHandler RowChanged;
\r
1684 /// Occurs when a DataRow is changing.
\r
1686 [DataCategory ("Data")]
\r
1688 [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.")]
\r
1690 public event DataRowChangeEventHandler RowChanging;
\r
1693 /// Occurs after a row in the table has been deleted.
\r
1695 [DataCategory ("Data")]
\r
1697 [DataSysDescription ("Occurs after a row in the table has been successfully deleted.")]
\r
1699 public event DataRowChangeEventHandler RowDeleted;
\r
1702 /// Occurs before a row in the table is about to be deleted.
\r
1704 [DataCategory ("Data")]
\r
1706 [DataSysDescription ("Occurs when a row in the table marked for deletion. Throw an exception to cancel the deletion.")]
\r
1708 public event DataRowChangeEventHandler RowDeleting;
\r
1710 #endregion // Events
\r
1712 internal static DataColumn[] ParseSortString (DataTable table, string sort, out ListSortDirection[] sortDirections, bool rejectNoResult)
\r
1714 DataColumn[] sortColumns = _emptyColumnArray;
\r
1715 sortDirections = null;
\r
1717 ArrayList columns = null;
\r
1718 ArrayList sorts = null;
\r
1720 if (sort != null && !sort.Equals ("")) {
\r
1721 columns = new ArrayList ();
\r
1722 sorts = new ArrayList();
\r
1723 string[] columnExpression = sort.Trim ().Split (new char[1] {','});
\r
1725 for (int c = 0; c < columnExpression.Length; c++) {
\r
1726 string rawColumnName = columnExpression[c].Trim ();
\r
1728 Match match = SortRegex.Match (rawColumnName);
\r
1729 Group g = match.Groups["ColName"] ;
\r
1731 throw new IndexOutOfRangeException ("Could not find column: " + rawColumnName);
\r
1733 string columnName = g.Value;
\r
1734 DataColumn dc = table.Columns[columnName];
\r
1737 dc = table.Columns[Int32.Parse (columnName)];
\r
1738 } catch (FormatException) {
\r
1739 throw new IndexOutOfRangeException("Cannot find column " + columnName);
\r
1744 g = match.Groups["Order"];
\r
1745 if (!g.Success || String.Compare (g.Value, "ASC", true, CultureInfo.InvariantCulture) == 0)
\r
1746 sorts.Add(ListSortDirection.Ascending);
\r
1748 sorts.Add (ListSortDirection.Descending);
\r
1751 sortColumns = (DataColumn[]) columns.ToArray (typeof (DataColumn));
\r
1752 sortDirections = new ListSortDirection[sorts.Count];
\r
1753 for (int i = 0; i < sortDirections.Length; i++)
\r
1754 sortDirections[i] = (ListSortDirection)sorts[i];
\r
1757 if (rejectNoResult) {
\r
1758 if (sortColumns == null)
\r
1759 throw new SystemException ("sort expression result is null");
\r
1760 if (sortColumns.Length == 0)
\r
1761 throw new SystemException("sort expression result is 0");
\r
1764 return sortColumns;
\r
1767 private void UpdatePropertyDescriptorsCache ()
\r
1769 PropertyDescriptor[] descriptors = new PropertyDescriptor[Columns.Count + ChildRelations.Count];
\r
1771 foreach (DataColumn col in Columns)
\r
1772 descriptors [index++] = new DataColumnPropertyDescriptor (col);
\r
1774 foreach (DataRelation rel in ChildRelations)
\r
1775 descriptors [index++] = new DataRelationPropertyDescriptor (rel);
\r
1777 _propertyDescriptorsCache = new PropertyDescriptorCollection (descriptors);
\r
1780 internal PropertyDescriptorCollection GetPropertyDescriptorCollection()
\r
1782 if (_propertyDescriptorsCache == null)
\r
1783 UpdatePropertyDescriptorsCache ();
\r
1784 return _propertyDescriptorsCache;
\r
1787 internal void ResetPropertyDescriptorsCache ()
\r
1789 _propertyDescriptorsCache = null;
\r
1792 internal void SetRowsID()
\r
1794 int dataRowID = 0;
\r
1795 foreach (DataRow row in Rows) {
\r
1796 row.XmlRowID = dataRowID;
\r
1803 [XmlSchemaProvider ("GetDataTableSchema")]
\r
1804 partial class DataTable : IXmlSerializable {
\r
1805 [MonoNotSupported ("")]
\r
1806 XmlSchema IXmlSerializable.GetSchema ()
\r
1808 return GetSchema ();
\r
1811 void IXmlSerializable.ReadXml (XmlReader reader)
\r
1813 ReadXml_internal (reader, true);
\r
1816 void IXmlSerializable.WriteXml (XmlWriter writer)
\r
1818 DataSet dset = dataSet;
\r
1819 bool isPartOfDataSet = true;
\r
1821 if (dataSet == null) {
\r
1822 dset = new DataSet ();
\r
1823 dset.Tables.Add (this);
\r
1824 isPartOfDataSet = false;
\r
1827 XmlSchemaWriter.WriteXmlSchema (writer, new DataTable [] { this },
\r
1828 null, TableName, dset.DataSetName, LocaleSpecified ? Locale : dset.LocaleSpecified ? dset.Locale : null);
\r
1829 dset.WriteIndividualTableContent (writer, this, XmlWriteMode.DiffGram);
\r
1832 if (!isPartOfDataSet)
\r
1833 dataSet.Tables.Remove(this);
\r
1837 protected virtual XmlSchema GetSchema ()
\r
1839 throw new NotImplementedException ();
\r
1842 public static XmlSchemaComplexType GetDataTableSchema (XmlSchemaSet schemaSet)
\r
1844 return new XmlSchemaComplexType ();
\r
1847 public XmlReadMode ReadXml (Stream stream)
\r
1849 return ReadXml (new XmlTextReader(stream, null));
\r
1852 public XmlReadMode ReadXml (string fileName)
\r
1854 XmlReader reader = new XmlTextReader (fileName);
\r
1856 return ReadXml (reader);
\r
1862 public XmlReadMode ReadXml (TextReader reader)
\r
1864 return ReadXml (new XmlTextReader (reader));
\r
1867 public XmlReadMode ReadXml (XmlReader reader)
\r
1869 return ReadXml_internal (reader, false);
\r
1872 public XmlReadMode ReadXml_internal (XmlReader reader, bool serializable)
\r
1874 // The documentation from MS for this method is rather
\r
1875 // poor. The following cases have been observed
\r
1876 // during testing:
\r
1878 // Reading a table from XML may create a DataSet to
\r
1879 // store child tables.
\r
1881 // If the table has at least one column present,
\r
1882 // we do not require the schema to be present in
\r
1883 // the xml. If the table has no columns, neither
\r
1884 // regular data nor diffgrams will be read, but
\r
1885 // will throw an error indicating that schema
\r
1886 // will not be inferred.
\r
1888 // We will likely need to take advantage of the
\r
1889 // msdata:MainDataTable attribute added to the
\r
1890 // schema info to load into the appropriate
\r
1892 bool isPartOfDataSet = true;
\r
1893 bool isTableNameBlank = false;
\r
1894 XmlReadMode mode = XmlReadMode.ReadSchema;
\r
1895 DataSet dataSet = null;
\r
1896 DataSet ds = new DataSet ();
\r
1898 reader.MoveToContent ();
\r
1899 if (Columns.Count > 0 && reader.LocalName != "diffgram" || serializable)
\r
1900 mode = ds.ReadXml (reader);
\r
1901 else if (Columns.Count > 0 && reader.LocalName == "diffgram") {
\r
1903 if (TableName == String.Empty)
\r
1904 isTableNameBlank = true;
\r
1905 if (DataSet == null) {
\r
1906 isPartOfDataSet = false;
\r
1907 ds.Tables.Add (this);
\r
1908 mode = ds.ReadXml (reader);
\r
1910 mode = DataSet.ReadXml (reader);
\r
1911 } catch (DataException) {
\r
1912 mode = XmlReadMode.DiffGram;
\r
1913 if (isTableNameBlank)
\r
1914 TableName = String.Empty;
\r
1916 if (!isPartOfDataSet)
\r
1917 ds.Tables.Remove (this);
\r
1921 mode = ds.ReadXml (reader, XmlReadMode.ReadSchema);
\r
1923 if (mode == XmlReadMode.InferSchema)
\r
1924 mode = XmlReadMode.IgnoreSchema;
\r
1925 if (DataSet == null) {
\r
1926 isPartOfDataSet = false;
\r
1927 dataSet = new DataSet ();
\r
1928 if (TableName == String.Empty)
\r
1929 isTableNameBlank = true;
\r
1930 dataSet.Tables.Add (this);
\r
1933 DenyXmlResolving (this, ds, mode, isTableNameBlank, isPartOfDataSet);
\r
1934 if (Columns.Count > 0 && TableName != ds.Tables [0].TableName) {
\r
1935 if (isPartOfDataSet == false)
\r
1936 dataSet.Tables.Remove (this);
\r
1938 if (isTableNameBlank && isPartOfDataSet == false)
\r
1939 TableName = String.Empty;
\r
1943 TableName = ds.Tables [0].TableName;
\r
1946 if (!isPartOfDataSet) {
\r
1947 if (Columns.Count > 0) {
\r
1948 dataSet.Merge (ds, true, MissingSchemaAction.Ignore);
\r
1950 dataSet.Merge (ds, true, MissingSchemaAction.AddWithKey);
\r
1952 if (ChildRelations.Count == 0) {
\r
1953 dataSet.Tables.Remove (this);
\r
1955 dataSet.DataSetName = ds.DataSetName;
\r
1958 if (Columns.Count > 0) {
\r
1959 DataSet.Merge (ds, true, MissingSchemaAction.Ignore);
\r
1961 DataSet.Merge (ds, true, MissingSchemaAction.AddWithKey);
\r
1967 private void DenyXmlResolving (DataTable table, DataSet ds, XmlReadMode mode, bool isTableNameBlank, bool isPartOfDataSet)
\r
1969 if (ds.Tables.Count == 0 && table.Columns.Count == 0)
\r
1970 throw new InvalidOperationException ("DataTable does not support schema inference from XML");
\r
1972 if (table.Columns.Count == 0 && ds.Tables [0].TableName != table.TableName && isTableNameBlank == false)
\r
1973 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
\r
1974 table.TableName));
\r
1976 if (table.Columns.Count > 0 && ds.Tables [0].TableName != table.TableName &&
\r
1977 isTableNameBlank == false && mode == XmlReadMode.ReadSchema &&
\r
1978 isPartOfDataSet == false)
\r
1979 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
\r
1980 table.TableName));
\r
1982 if (isPartOfDataSet == true && table.Columns.Count > 0 &&
\r
1983 mode == XmlReadMode.ReadSchema && table.TableName != ds.Tables [0].TableName)
\r
1984 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
\r
1985 table.TableName));
\r
1988 public void ReadXmlSchema (Stream stream)
\r
1990 ReadXmlSchema (new XmlTextReader (stream));
\r
1993 public void ReadXmlSchema (TextReader reader)
\r
1995 ReadXmlSchema (new XmlTextReader (reader));
\r
1998 public void ReadXmlSchema (string fileName)
\r
2000 XmlTextReader reader = null;
\r
2002 reader = new XmlTextReader (fileName);
\r
2003 ReadXmlSchema (reader);
\r
2005 if (reader != null)
\r
2010 public void ReadXmlSchema (XmlReader reader)
\r
2012 if (this.Columns.Count > 0)
\r
2015 DataSet ds = new DataSet ();
\r
2016 new XmlSchemaDataImporter (ds, reader, false).Process ();
\r
2017 DataTable target = null;
\r
2018 if (TableName == String.Empty) {
\r
2019 if (ds.Tables.Count > 0)
\r
2020 target = ds.Tables [0];
\r
2023 target = ds.Tables [TableName];
\r
2024 if (target == null)
\r
2025 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source.", TableName));
\r
2027 if (target != null)
\r
2028 target.CopyProperties (this);
\r
2031 [MonoNotSupported ("")]
\r
2032 protected virtual void ReadXmlSerializable (XmlReader reader)
\r
2034 throw new NotImplementedException ();
\r
2037 private XmlWriterSettings GetWriterSettings ()
\r
2039 XmlWriterSettings s = new XmlWriterSettings ();
\r
2041 s.OmitXmlDeclaration = true;
\r
2045 public void WriteXml (Stream stream)
\r
2047 WriteXml (stream, XmlWriteMode.IgnoreSchema, false);
\r
2050 public void WriteXml (TextWriter writer)
\r
2052 WriteXml (writer, XmlWriteMode.IgnoreSchema, false);
\r
2055 public void WriteXml (XmlWriter writer)
\r
2057 WriteXml (writer, XmlWriteMode.IgnoreSchema, false);
\r
2060 public void WriteXml (string fileName)
\r
2062 WriteXml (fileName, XmlWriteMode.IgnoreSchema, false);
\r
2065 public void WriteXml (Stream stream, XmlWriteMode mode)
\r
2067 WriteXml (stream, mode, false);
\r
2070 public void WriteXml (TextWriter writer, XmlWriteMode mode)
\r
2072 WriteXml (writer, mode, false);
\r
2075 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
\r
2077 WriteXml (writer, mode, false);
\r
2080 public void WriteXml (string fileName, XmlWriteMode mode)
\r
2082 WriteXml (fileName, mode, false);
\r
2085 public void WriteXml (Stream stream, bool writeHierarchy)
\r
2087 WriteXml (stream, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2090 public void WriteXml (string fileName, bool writeHierarchy)
\r
2092 WriteXml (fileName, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2095 public void WriteXml (TextWriter writer, bool writeHierarchy)
\r
2097 WriteXml (writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2100 public void WriteXml (XmlWriter writer, bool writeHierarchy)
\r
2102 WriteXml (writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2105 public void WriteXml (Stream stream, XmlWriteMode mode, bool writeHierarchy)
\r
2107 WriteXml (XmlWriter.Create (stream, GetWriterSettings ()), mode, writeHierarchy);
\r
2110 public void WriteXml (string fileName, XmlWriteMode mode, bool writeHierarchy)
\r
2112 XmlWriter xw = null;
\r
2114 xw = XmlWriter.Create (fileName, GetWriterSettings ());
\r
2115 WriteXml (xw, mode, writeHierarchy);
\r
2122 public void WriteXml (TextWriter writer, XmlWriteMode mode, bool writeHierarchy)
\r
2124 WriteXml (XmlWriter.Create (writer, GetWriterSettings ()), mode, writeHierarchy);
\r
2127 public void WriteXml (XmlWriter writer, XmlWriteMode mode, bool writeHierarchy)
\r
2129 // If we're in mode XmlWriteMode.WriteSchema, we need to output an extra
\r
2130 // msdata:MainDataTable attribute that wouldn't normally be part of the
\r
2131 // DataSet WriteXml output.
\r
2133 // For the writeHierarchy == true case, we write what would be output by
\r
2134 // a DataSet write, but we limit ourselves to our table and its descendants.
\r
2136 // For the writeHierarchy == false case, we write what would be output by
\r
2137 // a DataSet write, but we limit ourselves to this table.
\r
2139 // If the table is not in a DataSet, we follow the following behaviour:
\r
2140 // For WriteSchema cases, we do a write as if there is a wrapper
\r
2141 // dataset called NewDataSet.
\r
2142 // For IgnoreSchema or DiffGram cases, we do a write as if there
\r
2143 // is a wrapper dataset called DocumentElement.
\r
2145 // Generate a list of tables to write.
\r
2146 List <DataTable> tables = new List <DataTable> ();
\r
2147 if (writeHierarchy == false)
\r
2148 tables.Add (this);
\r
2150 FindAllChildren (tables, this);
\r
2152 // If we're in a DataSet, generate a list of relations to write.
\r
2153 List <DataRelation> relations = new List <DataRelation> ();
\r
2154 if (DataSet != null) {
\r
2155 foreach (DataRelation relation in DataSet.Relations) {
\r
2156 if (tables.Contains (relation.ParentTable) &&
\r
2157 tables.Contains (relation.ChildTable))
\r
2158 relations.Add (relation);
\r
2162 // Add the msdata:MainDataTable info if we're writing schema data.
\r
2163 string mainDataTable = null;
\r
2164 if (mode == XmlWriteMode.WriteSchema)
\r
2165 mainDataTable = this.TableName;
\r
2167 // Figure out the DataSet name.
\r
2168 string dataSetName = null;
\r
2169 if (DataSet != null)
\r
2170 dataSetName = DataSet.DataSetName;
\r
2171 else if (DataSet == null && mode == XmlWriteMode.WriteSchema)
\r
2172 dataSetName = "NewDataSet";
\r
2174 dataSetName = "DocumentElement";
\r
2176 XmlTableWriter.WriteTables(writer, mode, tables, relations, mainDataTable, dataSetName);
\r
2179 private void FindAllChildren(List<DataTable> list, DataTable root)
\r
2181 if (!list.Contains(root))
\r
2184 foreach (DataRelation relation in root.ChildRelations)
\r
2186 FindAllChildren(list, relation.ChildTable);
\r
2191 public void WriteXmlSchema (Stream stream)
\r
2193 if (TableName == "") {
\r
2194 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2196 XmlWriterSettings s = GetWriterSettings ();
\r
2197 s.OmitXmlDeclaration = false;
\r
2198 WriteXmlSchema (XmlWriter.Create (stream, s));
\r
2201 public void WriteXmlSchema (TextWriter writer)
\r
2203 if (TableName == "") {
\r
2204 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2206 XmlWriterSettings s = GetWriterSettings ();
\r
2207 s.OmitXmlDeclaration = false;
\r
2208 WriteXmlSchema (XmlWriter.Create (writer, s));
\r
2211 public void WriteXmlSchema (XmlWriter writer)
\r
2213 WriteXmlSchema (writer, false);
\r
2215 if (TableName == "") {
\r
2216 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2218 DataSet ds = DataSet;
\r
2219 DataSet tmp = null;
\r
2222 tmp = ds = new DataSet ();
\r
2223 ds.Tables.Add (this);
\r
2225 writer.WriteStartDocument ();
\r
2226 DataTableCollection col = new DataTableCollection (ds);
\r
2228 DataTable [] tables = new DataTable [col.Count];
\r
2229 for (int i = 0; i < col.Count; i++) tables[i] = col[i];
\r
2231 if (ds.Namespace == "")
\r
2232 tableName = TableName;
\r
2234 tableName = ds.Namespace + "_x003A_" + TableName;
\r
2235 XmlSchemaWriter.WriteXmlSchema (writer, tables, null, tableName, ds.DataSetName);
\r
2238 ds.Tables.Remove (this);
\r
2243 public void WriteXmlSchema (string fileName)
\r
2245 if (fileName == "") {
\r
2246 throw new ArgumentException ("Empty path name is not legal.");
\r
2248 if (TableName == "") {
\r
2249 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2251 XmlTextWriter writer = null;
\r
2253 XmlWriterSettings s = GetWriterSettings ();
\r
2254 s.OmitXmlDeclaration = false;
\r
2255 writer = new XmlTextWriter (fileName, null);
\r
2256 WriteXmlSchema (writer);
\r
2258 if (writer != null) {
\r
2264 public void WriteXmlSchema (Stream stream, bool writeHierarchy)
\r
2266 if (TableName == "") {
\r
2267 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2269 XmlWriterSettings s = GetWriterSettings ();
\r
2270 s.OmitXmlDeclaration = false;
\r
2271 WriteXmlSchema (XmlWriter.Create (stream, s), writeHierarchy);
\r
2274 public void WriteXmlSchema (TextWriter writer, bool writeHierarchy)
\r
2276 if (TableName == "") {
\r
2277 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2279 XmlWriterSettings s = GetWriterSettings ();
\r
2280 s.OmitXmlDeclaration = false;
\r
2281 WriteXmlSchema (XmlWriter.Create (writer, s), writeHierarchy);
\r
2284 public void WriteXmlSchema (XmlWriter writer, bool writeHierarchy)
\r
2286 if (TableName == "") {
\r
2287 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2289 // if (writeHierarchy == false) {
\r
2290 // WriteXmlSchema (writer);
\r
2293 DataSet ds = DataSet;
\r
2294 DataSet tmp = null;
\r
2297 tmp = ds = new DataSet ();
\r
2298 ds.Tables.Add (this);
\r
2300 writer.WriteStartDocument ();
\r
2301 //XmlSchemaWriter.WriteXmlSchema (ds, writer);
\r
2302 //DataTable [] tables = new DataTable [ds.Tables.Count];
\r
2303 DataTable [] tables = null;
\r
2304 //DataRelation [] relations = new DataRelation [ds.Relations.Count];
\r
2305 //for (int i = 0; i < ds.Relations.Count; i++) {
\r
2306 // relations[i] = ds.Relations[i];
\r
2308 DataRelation [] relations = null;
\r
2309 if (writeHierarchy && ChildRelations.Count > 0) {
\r
2310 relations = new DataRelation [ChildRelations.Count];
\r
2311 for (int i = 0; i < ChildRelations.Count; i++) {
\r
2312 relations [i] = ChildRelations [i];
\r
2314 tables = new DataTable [ds.Tables.Count];
\r
2315 for (int i = 0; i < ds.Tables.Count; i++) tables [i] = ds.Tables [i];
\r
2317 tables = new DataTable [1];
\r
2318 tables [0] = this;
\r
2322 if (ds.Namespace == "")
\r
2323 tableName = TableName;
\r
2325 tableName = ds.Namespace + "_x003A_" + TableName;
\r
2326 XmlSchemaWriter.WriteXmlSchema (writer, tables, relations, tableName, ds.DataSetName, LocaleSpecified ? Locale : ds.LocaleSpecified ? ds.Locale : null);
\r
2329 ds.Tables.Remove (this);
\r
2334 public void WriteXmlSchema (string fileName, bool writeHierarchy)
\r
2336 if (fileName == "") {
\r
2337 throw new ArgumentException ("Empty path name is not legal.");
\r
2339 if (TableName == "") {
\r
2340 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2342 XmlTextWriter writer = null;
\r
2344 XmlWriterSettings s = GetWriterSettings ();
\r
2345 s.OmitXmlDeclaration = false;
\r
2346 writer = new XmlTextWriter (fileName, null);
\r
2347 WriteXmlSchema (writer, writeHierarchy);
\r
2349 if (writer != null) {
\r
2356 partial class DataTable : ISupportInitializeNotification {
\r
2357 private bool tableInitialized = true;
\r
2359 [Browsable (false)]
\r
2360 public bool IsInitialized {
\r
2361 get { return tableInitialized; }
\r
2364 public event EventHandler Initialized;
\r
2366 private void OnTableInitialized (EventArgs e)
\r
2368 if (null != Initialized)
\r
2369 Initialized (this, e);
\r
2372 partial void DataTableInitialized ()
\r
2374 tableInitialized = true;
\r
2375 OnTableInitialized (new EventArgs ());
\r
2379 partial class DataTable {
\r
2380 public DataTable (string tableName, string tbNamespace)
\r
2381 : this (tableName)
\r
2383 _nameSpace = tbNamespace;
\r
2386 SerializationFormat remotingFormat = SerializationFormat.Xml;
\r
2387 [DefaultValue (SerializationFormat.Xml)]
\r
2388 public SerializationFormat RemotingFormat {
\r
2390 if (dataSet != null)
\r
2391 remotingFormat = dataSet.RemotingFormat;
\r
2392 return remotingFormat;
\r
2395 if (dataSet != null)
\r
2396 throw new ArgumentException ("Cannot have different remoting format property value for DataSet and DataTable");
\r
2397 remotingFormat = value;
\r
2401 internal void DeserializeConstraints (ArrayList arrayList)
\r
2403 bool fKeyNavigate = false;
\r
2404 for (int i = 0; i < arrayList.Count; i++) {
\r
2405 ArrayList tmpArrayList = arrayList [i] as ArrayList;
\r
2406 if (tmpArrayList == null)
\r
2408 if ((string) tmpArrayList [0] == "F") {
\r
2409 int [] constraintsArray = tmpArrayList [2] as int [];
\r
2411 if (constraintsArray == null)
\r
2413 ArrayList parentColumns = new ArrayList ();
\r
2414 DataTable dt = dataSet.Tables [constraintsArray [0]];
\r
2415 for (int j = 0; j < constraintsArray.Length - 1; j++) {
\r
2416 parentColumns.Add (dt.Columns [constraintsArray [j + 1]]);
\r
2419 constraintsArray = tmpArrayList [3] as int [];
\r
2421 if (constraintsArray == null)
\r
2423 ArrayList childColumns = new ArrayList ();
\r
2424 dt = dataSet.Tables [constraintsArray [0]];
\r
2425 for (int j = 0; j < constraintsArray.Length - 1; j++) {
\r
2426 childColumns.Add (dt.Columns [constraintsArray [j + 1]]);
\r
2429 ForeignKeyConstraint fKeyConstraint = new
\r
2430 ForeignKeyConstraint ((string) tmpArrayList [1],
\r
2431 (DataColumn []) parentColumns.ToArray (typeof (DataColumn)),
\r
2432 (DataColumn []) childColumns.ToArray (typeof (DataColumn)));
\r
2433 Array ruleArray = (Array) tmpArrayList [4];
\r
2434 fKeyConstraint.AcceptRejectRule = (AcceptRejectRule) ruleArray.GetValue (0);
\r
2435 fKeyConstraint.UpdateRule = (Rule) ruleArray.GetValue (1);
\r
2436 fKeyConstraint.DeleteRule = (Rule) ruleArray.GetValue (2);
\r
2437 // FIXME: refactor this deserialization code out to ForeighKeyConstraint
\r
2438 fKeyConstraint.SetExtendedProperties ((PropertyCollection) tmpArrayList [5]);
\r
2439 Constraints.Add (fKeyConstraint);
\r
2440 fKeyNavigate = true;
\r
2441 } else if (fKeyNavigate == false &&
\r
2442 (string) tmpArrayList [0] == "U") {
\r
2443 UniqueConstraint unique = null;
\r
2444 ArrayList uniqueDataColumns = new ArrayList ();
\r
2445 int [] constraintsArray = tmpArrayList [2] as int [];
\r
2447 if (constraintsArray == null)
\r
2450 for (int j = 0; j < constraintsArray.Length; j++) {
\r
2451 uniqueDataColumns.Add (Columns [constraintsArray [j]]);
\r
2453 unique = new UniqueConstraint ((string) tmpArrayList[1],
\r
2454 (DataColumn[]) uniqueDataColumns.
\r
2455 ToArray (typeof (DataColumn)),
\r
2456 (bool) tmpArrayList [3]);
\r
2458 If UniqueConstraint already exist, don't add them
\r
2460 if (Constraints.IndexOf (unique) != -1 ||
\r
2461 Constraints.IndexOf ((string) tmpArrayList[1]) != -1) {
\r
2464 // FIXME: refactor this deserialization code out to UniqueConstraint
\r
2465 unique.SetExtendedProperties ((PropertyCollection) tmpArrayList [4]);
\r
2466 Constraints.Add (unique);
\r
2468 fKeyNavigate = false;
\r
2473 DataRowState GetCurrentRowState (BitArray rowStateBitArray, int i)
\r
2475 DataRowState currentRowState;
\r
2476 if (rowStateBitArray[i] == false &&
\r
2477 rowStateBitArray[i+1] == false &&
\r
2478 rowStateBitArray[i+2] == true)
\r
2479 currentRowState = DataRowState.Detached;
\r
2480 else if (rowStateBitArray[i] == false &&
\r
2481 rowStateBitArray[i+1] == false &&
\r
2482 rowStateBitArray[i+2] == false)
\r
2483 currentRowState = DataRowState.Unchanged;
\r
2484 else if (rowStateBitArray[i] == false &&
\r
2485 rowStateBitArray[i+1] == true &&
\r
2486 rowStateBitArray[i+2] == false)
\r
2487 currentRowState = DataRowState.Added;
\r
2488 else if (rowStateBitArray[i] == true &&
\r
2489 rowStateBitArray[i+1] == true &&
\r
2490 rowStateBitArray[i+2] == false)
\r
2491 currentRowState = DataRowState.Deleted;
\r
2493 currentRowState = DataRowState.Modified;
\r
2494 return currentRowState;
\r
2497 internal void DeserializeRecords (ArrayList arrayList, ArrayList nullBits, BitArray rowStateBitArray)
\r
2499 BitArray nullBit = null;
\r
2500 if (arrayList == null || arrayList.Count < 1)
\r
2502 int len = ((Array) arrayList [0]).Length;
\r
2503 object [] tmpArray = new object [arrayList.Count];
\r
2505 DataRowState currentRowState;
\r
2506 for (int l = 0; l < len; l++) { // Columns
\r
2507 currentRowState = GetCurrentRowState (rowStateBitArray, k *3);
\r
2508 for (int j = 0; j < arrayList.Count; j++) { // Rows
\r
2509 Array array = (Array) arrayList [j];
\r
2510 nullBit = (BitArray) nullBits [j];
\r
2511 if (nullBit [l] == false) {
\r
2512 tmpArray [j] = array.GetValue (l);
\r
2514 tmpArray [j] = null;
\r
2517 LoadDataRow (tmpArray, false);
\r
2518 if (currentRowState == DataRowState.Modified) {
\r
2519 Rows[k].AcceptChanges ();
\r
2521 for (int j = 0; j < arrayList.Count; j++) {
\r
2522 Array array = (Array) arrayList [j];
\r
2523 nullBit = (BitArray) nullBits[j];
\r
2524 if (nullBit [l] == false) {
\r
2525 Rows [k][j] = array.GetValue (l);
\r
2527 Rows [k][j] = null;
\r
2530 } else if (currentRowState == DataRowState.Unchanged) {
\r
2531 Rows[k].AcceptChanges ();
\r
2532 } else if (currentRowState == DataRowState.Deleted) {
\r
2533 Rows[k].AcceptChanges ();
\r
2534 Rows[k].Delete ();
\r
2540 void BinaryDeserializeTable (SerializationInfo info)
\r
2542 ArrayList arrayList = null;
\r
2544 TableName = info.GetString ("DataTable.TableName");
\r
2545 Namespace = info.GetString ("DataTable.Namespace");
\r
2546 Prefix = info.GetString ("DataTable.Prefix");
\r
2547 CaseSensitive = info.GetBoolean ("DataTable.CaseSensitive");
\r
2549 FIXME: Private variable available in SerializationInfo
\r
2550 this.caseSensitiveAmbientCaseSensitive = info.GetBoolean("DataTable.caseSensitiveAmbientCaseSensitive");
\r
2551 this.NestedInDataSet = info.GetBoolean("DataTable.NestedInDataSet");
\r
2552 this.RepeatableElement = info.GetBoolean("DataTable.RepeatableElement");
\r
2553 this.RemotingVersion = (System.Version) info.GetValue("DataTable.RemotingVersion",
\r
2554 typeof(System.Version));
\r
2556 Locale = new CultureInfo (info.GetInt32 ("DataTable.LocaleLCID"));
\r
2557 _extendedProperties = (PropertyCollection) info.GetValue ("DataTable.ExtendedProperties",
\r
2558 typeof (PropertyCollection));
\r
2559 MinimumCapacity = info.GetInt32 ("DataTable.MinimumCapacity");
\r
2560 int columnsCount = info.GetInt32 ("DataTable.Columns.Count");
\r
2562 for (int i = 0; i < columnsCount; i++) {
\r
2564 string prefix = "DataTable.DataColumn_" + i + ".";
\r
2565 Columns[i].ColumnName = info.GetString (prefix + "ColumnName");
\r
2566 Columns[i].Namespace = info.GetString (prefix + "Namespace");
\r
2567 Columns[i].Caption = info.GetString (prefix + "Caption");
\r
2568 Columns[i].Prefix = info.GetString (prefix + "Prefix");
\r
2569 Columns[i].DataType = (Type) info.GetValue (prefix + "DataType",
\r
2571 Columns[i].DefaultValue = info.GetValue (prefix + "DefaultValue",
\r
2573 Columns[i].AllowDBNull = info.GetBoolean (prefix + "AllowDBNull");
\r
2574 Columns[i].AutoIncrement = info.GetBoolean (prefix + "AutoIncrement");
\r
2575 Columns[i].AutoIncrementStep = info.GetInt64 (prefix + "AutoIncrementStep");
\r
2576 Columns[i].AutoIncrementSeed = info.GetInt64(prefix + "AutoIncrementSeed");
\r
2577 Columns[i].ReadOnly = info.GetBoolean (prefix + "ReadOnly");
\r
2578 Columns[i].MaxLength = info.GetInt32 (prefix + "MaxLength");
\r
2580 FIXME: Private variable available in SerializationInfo
\r
2581 this.Columns[i].SimpleType = info.GetString("DataTable.DataColumn_" +
\r
2582 i + ".SimpleType");
\r
2583 this.Columns[i].AutoIncrementCurrent = info.GetInt64("DataTable.DataColumn_" +
\r
2584 i + ".AutoIncrementCurrent");
\r
2585 this.Columns[i].XmlDataType = info.GetString("DataTable.DataColumn_" +
\r
2586 i + ".XmlDataType");
\r
2588 Columns[i].ExtendedProperties = (PropertyCollection) info.GetValue (prefix + "ExtendedProperties",
\r
2589 typeof (PropertyCollection));
\r
2590 if (Columns[i].DataType == typeof (DataSetDateTime)) {
\r
2591 Columns[i].DateTimeMode = (DataSetDateTime) info.GetValue (prefix + "DateTimeMode",
\r
2592 typeof (DataSetDateTime));
\r
2594 Columns[i].ColumnMapping = (MappingType) info.GetValue (prefix + "ColumnMapping",
\r
2595 typeof (MappingType));
\r
2597 Columns[i].Expression = info.GetString (prefix + "Expression");
\r
2599 prefix = "DataTable_0.";
\r
2601 arrayList = (ArrayList) info.GetValue (prefix + "Constraints",
\r
2602 typeof (ArrayList));
\r
2603 if (Constraints == null)
\r
2604 Constraints = new ConstraintCollection (this);
\r
2605 DeserializeConstraints (arrayList);
\r
2606 } catch (SerializationException) {
\r
2610 String prefix = "DataTable_0.";
\r
2611 ArrayList nullBits = (ArrayList) info.GetValue (prefix + "NullBits",
\r
2612 typeof (ArrayList));
\r
2613 arrayList = (ArrayList) info.GetValue (prefix + "Records",
\r
2614 typeof (ArrayList));
\r
2615 BitArray rowStateBitArray = (BitArray) info.GetValue (prefix + "RowStates",
\r
2616 typeof (BitArray));
\r
2617 Hashtable htRowErrors = (Hashtable) info.GetValue (prefix + "RowErrors",
\r
2618 typeof (Hashtable));
\r
2619 DeserializeRecords (arrayList, nullBits, rowStateBitArray);
\r
2620 } catch (SerializationException) {
\r
2624 internal void BinarySerializeProperty (SerializationInfo info)
\r
2626 Version vr = new Version (2, 0);
\r
2627 info.AddValue ("DataTable.RemotingVersion", vr);
\r
2628 info.AddValue ("DataTable.RemotingFormat", RemotingFormat);
\r
2629 info.AddValue ("DataTable.TableName", TableName);
\r
2630 info.AddValue ("DataTable.Namespace", Namespace);
\r
2631 info.AddValue ("DataTable.Prefix", Prefix);
\r
2632 info.AddValue ("DataTable.CaseSensitive", CaseSensitive);
\r
2634 FIXME: Required by MS.NET
\r
2635 caseSensitiveAmbient, NestedInDataSet, RepeatableElement
\r
2637 info.AddValue ("DataTable.caseSensitiveAmbient", true);
\r
2638 info.AddValue ("DataTable.NestedInDataSet", true);
\r
2639 info.AddValue ("DataTable.RepeatableElement", false);
\r
2640 info.AddValue ("DataTable.LocaleLCID", Locale.LCID);
\r
2641 info.AddValue ("DataTable.MinimumCapacity", MinimumCapacity);
\r
2642 info.AddValue ("DataTable.Columns.Count", Columns.Count);
\r
2643 info.AddValue ("DataTable.ExtendedProperties", _extendedProperties);
\r
2644 for (int i = 0; i < Columns.Count; i++) {
\r
2645 info.AddValue ("DataTable.DataColumn_" + i + ".ColumnName",
\r
2646 Columns[i].ColumnName);
\r
2647 info.AddValue ("DataTable.DataColumn_" + i + ".Namespace",
\r
2648 Columns[i].Namespace);
\r
2649 info.AddValue ("DataTable.DataColumn_" + i + ".Caption",
\r
2650 Columns[i].Caption);
\r
2651 info.AddValue ("DataTable.DataColumn_" + i + ".Prefix",
\r
2652 Columns[i].Prefix);
\r
2653 info.AddValue ("DataTable.DataColumn_" + i + ".DataType",
\r
2654 Columns[i].DataType, typeof (Type));
\r
2655 info.AddValue ("DataTable.DataColumn_" + i + ".DefaultValue",
\r
2656 Columns[i].DefaultValue, typeof (DBNull));
\r
2657 info.AddValue ("DataTable.DataColumn_" + i + ".AllowDBNull",
\r
2658 Columns[i].AllowDBNull);
\r
2659 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrement",
\r
2660 Columns[i].AutoIncrement);
\r
2661 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementStep",
\r
2662 Columns[i].AutoIncrementStep);
\r
2663 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementSeed",
\r
2664 Columns[i].AutoIncrementSeed);
\r
2665 info.AddValue ("DataTable.DataColumn_" + i + ".ReadOnly",
\r
2666 Columns[i].ReadOnly);
\r
2667 info.AddValue ("DataTable.DataColumn_" + i + ".MaxLength",
\r
2668 Columns[i].MaxLength);
\r
2669 info.AddValue ("DataTable.DataColumn_" + i + ".ExtendedProperties",
\r
2670 Columns[i].ExtendedProperties);
\r
2671 info.AddValue ("DataTable.DataColumn_" + i + ".DateTimeMode",
\r
2672 Columns[i].DateTimeMode);
\r
2673 info.AddValue ("DataTable.DataColumn_" + i + ".ColumnMapping",
\r
2674 Columns[i].ColumnMapping, typeof (MappingType));
\r
2676 FIXME: Required by MS.NET
\r
2677 SimpleType, AutoIncrementCurrent, XmlDataType
\r
2679 info.AddValue ("DataTable.DataColumn_" + i + ".SimpleType",
\r
2680 null, typeof (string));
\r
2681 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementCurrent",
\r
2682 Columns[i].AutoIncrementValue());
\r
2683 info.AddValue ("DataTable.DataColumn_" + i + ".XmlDataType",
\r
2684 null, typeof (string));
\r
2687 FIXME: Required by MS.NET
\r
2690 info.AddValue ("DataTable.TypeName", null, typeof (string));
\r
2693 internal void SerializeConstraints (SerializationInfo info, string prefix)
\r
2695 ArrayList constraintArrayList = new ArrayList ();
\r
2696 for (int j = 0; j < Constraints.Count; j++) {
\r
2697 ArrayList constraintList = new ArrayList ();
\r
2698 if (Constraints[j] is UniqueConstraint) {
\r
2699 constraintList.Add ("U");
\r
2700 UniqueConstraint unique = (UniqueConstraint) Constraints [j];
\r
2701 constraintList.Add (unique.ConstraintName);
\r
2702 DataColumn [] columns = unique.Columns;
\r
2703 int [] tmpArray = new int [columns.Length];
\r
2704 for (int k = 0; k < columns.Length; k++)
\r
2705 tmpArray [k] = unique.Table.Columns.IndexOf (unique.Columns [k]);
\r
2706 constraintList.Add (tmpArray);
\r
2707 constraintList.Add (unique.IsPrimaryKey);
\r
2708 constraintList.Add (unique.ExtendedProperties);
\r
2709 } else if (Constraints[j] is ForeignKeyConstraint) {
\r
2710 constraintList.Add ("F");
\r
2711 ForeignKeyConstraint fKey = (ForeignKeyConstraint) Constraints [j];
\r
2712 constraintList.Add (fKey.ConstraintName);
\r
2714 int [] tmpArray = new int [fKey.RelatedColumns.Length + 1];
\r
2715 tmpArray [0] = DataSet.Tables.IndexOf (fKey.RelatedTable);
\r
2716 for (int i = 0; i < fKey.Columns.Length; i++) {
\r
2717 tmpArray [i + 1] = fKey.RelatedColumns [i].Ordinal;
\r
2719 constraintList.Add (tmpArray);
\r
2721 tmpArray = new int [fKey.Columns.Length + 1];
\r
2722 tmpArray [0] = DataSet.Tables.IndexOf (fKey.Table);
\r
2723 for (int i = 0; i < fKey.Columns.Length; i++) {
\r
2724 tmpArray [i + 1] = fKey.Columns [i].Ordinal;
\r
2726 constraintList.Add (tmpArray);
\r
2728 tmpArray = new int [3];
\r
2729 tmpArray [0] = (int) fKey.AcceptRejectRule;
\r
2730 tmpArray [1] = (int) fKey.UpdateRule;
\r
2731 tmpArray [2] = (int) fKey.DeleteRule;
\r
2732 constraintList.Add (tmpArray);
\r
2734 constraintList.Add (fKey.ExtendedProperties);
\r
2738 constraintArrayList.Add (constraintList);
\r
2740 info.AddValue (prefix, constraintArrayList, typeof (ArrayList));
\r
2743 internal void BinarySerialize (SerializationInfo info, string prefix)
\r
2745 int columnsCount = Columns.Count;
\r
2746 int rowsCount = Rows.Count;
\r
2747 int recordsCount = Rows.Count;
\r
2748 ArrayList recordList = new ArrayList ();
\r
2749 ArrayList bitArrayList = new ArrayList ();
\r
2750 BitArray rowStateBitArray = new BitArray (rowsCount * 3);
\r
2751 for (int k = 0; k < Rows.Count; k++) {
\r
2752 if (Rows[k].RowState == DataRowState.Modified)
\r
2755 SerializeConstraints (info, prefix + "Constraints");
\r
2756 for (int j = 0; j < columnsCount; j++) {
\r
2757 if (rowsCount == 0)
\r
2759 BitArray nullBits = new BitArray (rowsCount);
\r
2760 Array recordArray = Array.CreateInstance (Rows[0][j].GetType (), recordsCount);
\r
2761 DataColumn column = Columns [j];
\r
2762 for (int k = 0, l = 0; k < Rows.Count; k++, l++) {
\r
2763 DataRowVersion version;
\r
2764 DataRow dr = Rows[k];
\r
2765 if (dr.RowState == DataRowState.Modified) {
\r
2766 version = DataRowVersion.Default;
\r
2767 nullBits.Length = nullBits.Length + 1;
\r
2768 if (dr.IsNull (column, version) == false) {
\r
2769 nullBits [l] = false;
\r
2770 recordArray.SetValue (dr [j, version], l);
\r
2772 nullBits [l] = true;
\r
2775 version = DataRowVersion.Current;
\r
2776 } else if (dr.RowState == DataRowState.Deleted) {
\r
2777 version = DataRowVersion.Original;
\r
2779 version = DataRowVersion.Default;
\r
2781 if (dr.IsNull (column, version) == false) {
\r
2782 nullBits [l] = false;
\r
2783 recordArray.SetValue (dr [j, version], l);
\r
2785 nullBits [l] = true;
\r
2788 recordList.Add (recordArray);
\r
2789 bitArrayList.Add (nullBits);
\r
2791 for (int j = 0; j < Rows.Count; j++) {
\r
2793 DataRowState rowState = Rows [j].RowState;
\r
2794 if (rowState == DataRowState.Detached) {
\r
2795 rowStateBitArray [l] = false;
\r
2796 rowStateBitArray [l + 1] = false;
\r
2797 rowStateBitArray [l + 2] = true;
\r
2798 } else if (rowState == DataRowState.Unchanged) {
\r
2799 rowStateBitArray [l] = false;
\r
2800 rowStateBitArray [l + 1] = false;
\r
2801 rowStateBitArray [l + 2] = false;
\r
2802 } else if (rowState == DataRowState.Added) {
\r
2803 rowStateBitArray [l] = false;
\r
2804 rowStateBitArray [l + 1] = true;
\r
2805 rowStateBitArray [l + 2] = false;
\r
2806 } else if (rowState == DataRowState.Deleted) {
\r
2807 rowStateBitArray [l] = true;
\r
2808 rowStateBitArray [l + 1] = true;
\r
2809 rowStateBitArray [l + 2] = false;
\r
2811 rowStateBitArray [l] = true;
\r
2812 rowStateBitArray [l + 1] = false;
\r
2813 rowStateBitArray [l + 2] = false;
\r
2816 info.AddValue (prefix + "Rows.Count", Rows.Count);
\r
2817 info.AddValue (prefix + "Records.Count", recordsCount);
\r
2818 info.AddValue (prefix + "Records", recordList, typeof (ArrayList));
\r
2819 info.AddValue (prefix + "NullBits", bitArrayList, typeof (ArrayList));
\r
2820 info.AddValue (prefix + "RowStates",
\r
2821 rowStateBitArray, typeof (BitArray));
\r
2822 // FIXME: To get row errors
\r
2823 Hashtable htRowErrors = new Hashtable ();
\r
2824 info.AddValue (prefix + "RowErrors",
\r
2825 htRowErrors, typeof (Hashtable));
\r
2826 // FIXME: To get column errors
\r
2827 Hashtable htColumnErrors = new Hashtable ();
\r
2828 info.AddValue (prefix + "ColumnErrors",
\r
2829 htColumnErrors, typeof (Hashtable));
\r
2832 public DataTableReader CreateDataReader ()
\r
2834 return new DataTableReader (this);
\r
2838 /// Loads the table with the values from the reader
\r
2840 public void Load (IDataReader reader)
\r
2842 if (reader == null)
\r
2843 throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
\r
2844 Load (reader, LoadOption.PreserveChanges);
\r
2848 /// Loads the table with the values from the reader and the pattern
\r
2849 /// of the changes to the existing rows or the new rows are based on
\r
2850 /// the LoadOption passed.
\r
2852 public void Load (IDataReader reader, LoadOption loadOption)
\r
2854 if (reader == null)
\r
2855 throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
\r
2856 bool prevEnforceConstr = this.EnforceConstraints;
\r
2858 this.EnforceConstraints = false;
\r
2859 int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped,
\r
2860 MissingSchemaAction.AddWithKey,
\r
2861 MissingMappingAction.Passthrough,
\r
2862 new DataTableMappingCollection ());
\r
2863 DbDataAdapter.FillFromReader (this,
\r
2870 this.EnforceConstraints = prevEnforceConstr;
\r
2874 public virtual void Load (IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler)
\r
2876 if (reader == null)
\r
2877 throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
\r
2879 bool prevEnforceConstr = this.EnforceConstraints;
\r
2881 this.EnforceConstraints = false;
\r
2883 int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped,
\r
2884 MissingSchemaAction.AddWithKey,
\r
2885 MissingMappingAction.Passthrough,
\r
2886 new DataTableMappingCollection ());
\r
2887 DbDataAdapter.FillFromReader (this,
\r
2895 this.EnforceConstraints = prevEnforceConstr;
\r
2900 /// Loads the given values into an existing row if matches or creates
\r
2901 /// the new row popluated with the values.
\r
2904 /// This method searches for the values using primary keys and it first
\r
2905 /// searches using the original values of the rows and if not found, it
\r
2906 /// searches using the current version of the row.
\r
2908 public DataRow LoadDataRow (object [] values, LoadOption loadOption)
\r
2910 DataRow row = null;
\r
2912 // Find Data DataRow
\r
2913 if (this.PrimaryKey.Length > 0) {
\r
2914 object [] keys = new object [PrimaryKey.Length];
\r
2915 for (int i = 0; i < PrimaryKey.Length; i++)
\r
2916 keys [i] = values [PrimaryKey [i].Ordinal];
\r
2918 row = Rows.Find (keys, DataViewRowState.OriginalRows);
\r
2920 row = Rows.Find (keys);
\r
2923 // If not found, add new row
\r
2924 if (row == null ||
\r
2925 (row.RowState == DataRowState.Deleted && loadOption == LoadOption.Upsert)) {
\r
2926 row = NewNotInitializedRow ();
\r
2927 row.ImportRecord (CreateRecord (values));
\r
2929 row.Validate (); // this adds to index ;-)
\r
2931 if (loadOption == LoadOption.OverwriteChanges ||
\r
2932 loadOption == LoadOption.PreserveChanges)
\r
2933 Rows.AddInternal (row, DataRowAction.ChangeCurrentAndOriginal);
\r
2935 Rows.AddInternal(row);
\r
2939 row.Load (values, loadOption);
\r
2944 public void Merge (DataTable table)
\r
2946 Merge (table, false, MissingSchemaAction.Add);
\r
2949 public void Merge (DataTable table, bool preserveChanges)
\r
2951 Merge (table, preserveChanges, MissingSchemaAction.Add);
\r
2954 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
\r
2956 MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
\r
2959 internal int CompareRecords (int x, int y)
\r
2961 for (int col = 0; col < Columns.Count; col++) {
\r
2962 int res = Columns[col].DataContainer.CompareValues (x, y);
\r
2971 /// Occurs after the Clear method is called on the datatable.
\r
2973 [DataCategory ("Data")]
\r
2974 public event DataTableClearEventHandler TableCleared;
\r
2976 [DataCategory ("Data")]
\r
2977 public event DataTableClearEventHandler TableClearing;
\r
2979 public event DataTableNewRowEventHandler TableNewRow;
\r
2982 /// Raises TableCleared Event and delegates to subscribers
\r
2984 protected virtual void OnTableCleared (DataTableClearEventArgs e)
\r
2986 if (TableCleared != null)
\r
2987 TableCleared (this, e);
\r
2990 partial void DataTableCleared ()
\r
2992 OnTableCleared (new DataTableClearEventArgs (this));
\r
2995 protected virtual void OnTableClearing (DataTableClearEventArgs e)
\r
2997 if (TableClearing != null)
\r
2998 TableClearing (this, e);
\r
3001 partial void DataTableClearing ()
\r
3003 OnTableClearing (new DataTableClearEventArgs (this));
\r
3006 protected virtual void OnTableNewRow (DataTableNewRowEventArgs e)
\r
3008 if (null != TableNewRow)
\r
3009 TableNewRow (this, e);
\r
3012 partial void NewRowAdded (DataRow dr)
\r
3014 OnTableNewRow (new DataTableNewRowEventArgs (dr));
\r