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
46 using System.Collections.Generic;
\r
47 using System.ComponentModel;
\r
48 using System.Globalization;
\r
50 using System.Runtime.Serialization;
\r
52 using System.Xml.Schema;
\r
53 using System.Xml.Serialization;
\r
54 using System.Text.RegularExpressions;
\r
55 using Mono.Data.SqlExpressions;
\r
57 namespace System.Data {
\r
59 [ToolboxItem (false)]
\r
60 [DefaultEvent ("RowChanging")]
\r
61 [DefaultProperty ("TableName")]
\r
62 [DesignTimeVisible (false)]
\r
63 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DataTableEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
\r
65 public partial class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable {
\r
68 internal DataSet dataSet;
\r
70 private bool _caseSensitive;
\r
71 private DataColumnCollection _columnCollection;
\r
72 private ConstraintCollection _constraintCollection;
\r
73 // never access it. Use DefaultView.
\r
74 private DataView _defaultView = null;
\r
76 private string _displayExpression;
\r
77 private PropertyCollection _extendedProperties;
\r
78 private CultureInfo _locale;
\r
79 private int _minimumCapacity;
\r
80 private string _nameSpace;
\r
81 private DataRelationCollection _childRelations;
\r
82 private DataRelationCollection _parentRelations;
\r
83 private string _prefix;
\r
84 private UniqueConstraint _primaryKeyConstraint;
\r
85 private DataRowCollection _rows;
\r
86 private ISite _site;
\r
87 private string _tableName;
\r
88 internal bool _duringDataLoad;
\r
89 internal bool _nullConstraintViolationDuringDataLoad;
\r
90 private bool dataSetPrevEnforceConstraints;
\r
91 private bool enforceConstraints = true;
\r
92 private DataRowBuilder _rowBuilder;
\r
93 private ArrayList _indexes;
\r
94 private RecordCache _recordCache;
\r
95 private int _defaultValuesRowIndex = -1;
\r
96 protected internal bool fInitInProgress;
\r
98 // If CaseSensitive property is changed once it does not anymore follow owner DataSet's
\r
99 // CaseSensitive property. So when you lost you virginity it's gone for ever
\r
100 private bool _virginCaseSensitive = true;
\r
102 private PropertyDescriptorCollection _propertyDescriptorsCache;
\r
103 static DataColumn[] _emptyColumnArray = new DataColumn[0];
\r
105 // Regex to parse the Sort string.
\r
106 static Regex SortRegex = new Regex ( @"^((\[(?<ColName>.+)\])|(?<ColName>\S+))([ ]+(?<Order>ASC|DESC))?$",
\r
107 RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture);
\r
110 DataColumn [] _latestPrimaryKeyCols;
\r
111 #endregion //Fields
\r
114 /// Initializes a new instance of the DataTable class with no arguments.
\r
116 public DataTable ()
\r
119 _columnCollection = new DataColumnCollection(this);
\r
120 _constraintCollection = new ConstraintCollection(this);
\r
121 _extendedProperties = new PropertyCollection();
\r
124 _caseSensitive = false; //default value
\r
125 _displayExpression = null;
\r
126 _primaryKeyConstraint = null;
\r
128 _rows = new DataRowCollection (this);
\r
129 _indexes = new ArrayList();
\r
130 _recordCache = new RecordCache(this);
\r
132 //LAMESPEC: spec says 25 impl does 50
\r
133 _minimumCapacity = 50;
\r
135 _childRelations = new DataRelationCollection.DataTableRelationCollection (this);
\r
136 _parentRelations = new DataRelationCollection.DataTableRelationCollection (this);
\r
140 /// Intitalizes a new instance of the DataTable class with the specified table name.
\r
142 public DataTable (string tableName)
\r
145 _tableName = tableName;
\r
149 /// Initializes a new instance of the DataTable class with the SerializationInfo and the StreamingContext.
\r
151 protected DataTable (SerializationInfo info, StreamingContext context)
\r
154 SerializationInfoEnumerator e = info.GetEnumerator ();
\r
155 SerializationFormat serializationFormat = SerializationFormat.Xml;
\r
157 while (e.MoveNext()) {
\r
158 if (e.ObjectType == typeof(System.Data.SerializationFormat)) {
\r
159 serializationFormat = (SerializationFormat) e.Value;
\r
163 if (serializationFormat == SerializationFormat.Xml) {
\r
164 string schema = info.GetString ("XmlSchema");
\r
165 string data = info.GetString ("XmlDiffGram");
\r
167 DataSet ds = new DataSet ();
\r
168 ds.ReadXmlSchema (new StringReader (schema));
\r
169 ds.Tables [0].CopyProperties (this);
\r
170 ds = new DataSet ();
\r
171 ds.Tables.Add (this);
\r
172 ds.ReadXml (new StringReader (data), XmlReadMode.DiffGram);
\r
173 ds.Tables.Remove (this);
\r
174 /* keeping for a while. With the change above, we shouldn't have to consider
\r
175 * DataTable mode in schema inference/read.
\r
176 XmlSchemaMapper mapper = new XmlSchemaMapper (this);
\r
177 XmlTextReader xtr = new XmlTextReader(new StringReader (schema));
\r
180 XmlDiffLoader loader = new XmlDiffLoader (this);
\r
181 xtr = new XmlTextReader(new StringReader (data));
\r
184 } else /*if (Tables.RemotingFormat == SerializationFormat.Binary)*/ {
\r
185 BinaryDeserializeTable (info);
\r
190 /// Indicates whether string comparisons within the table are case-sensitive.
\r
192 public bool CaseSensitive {
\r
194 if (_virginCaseSensitive && dataSet != null)
\r
195 return dataSet.CaseSensitive;
\r
197 return _caseSensitive;
\r
200 if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
\r
201 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
203 _virginCaseSensitive = false;
\r
204 _caseSensitive = value;
\r
205 ResetCaseSensitiveIndexes();
\r
209 internal ArrayList Indexes {
\r
210 get { return _indexes; }
\r
213 internal void ChangedDataColumn (DataRow dr, DataColumn dc, object pv)
\r
215 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
\r
216 OnColumnChanged (e);
\r
219 internal void ChangingDataColumn (DataRow dr, DataColumn dc, object pv)
\r
221 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
\r
222 OnColumnChanging (e);
\r
225 internal void DeletedDataRow (DataRow dr, DataRowAction action)
\r
227 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
231 internal void DeletingDataRow (DataRow dr, DataRowAction action)
\r
233 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
237 internal void ChangedDataRow (DataRow dr, DataRowAction action)
\r
239 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
243 internal void ChangingDataRow (DataRow dr, DataRowAction action)
\r
245 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
\r
250 /// Gets the collection of child relations for this DataTable.
\r
252 [Browsable (false)]
\r
253 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
254 public DataRelationCollection ChildRelations {
\r
255 get { return _childRelations; }
\r
259 /// Gets the collection of columns that belong to this table.
\r
261 [DataCategory ("Data")]
\r
262 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
\r
263 public DataColumnCollection Columns {
\r
264 get { return _columnCollection; }
\r
268 /// Gets the collection of constraints maintained by this table.
\r
270 [DataCategory ("Data")]
\r
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
\r
272 public ConstraintCollection Constraints {
\r
273 get { return _constraintCollection; }
\r
274 internal set { _constraintCollection = value; }
\r
278 /// Gets the DataSet that this table belongs to.
\r
280 [Browsable (false)]
\r
281 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
282 public DataSet DataSet {
\r
283 get { return dataSet; }
\r
287 /// Gets a customized view of the table which may
\r
288 /// include a filtered view, or a cursor position.
\r
290 [Browsable (false)]
\r
291 public DataView DefaultView {
\r
293 if (_defaultView == null) {
\r
295 if (_defaultView == null){
\r
296 if (dataSet != null)
\r
297 _defaultView = dataSet.DefaultViewManager.CreateDataView(this);
\r
299 _defaultView = new DataView(this);
\r
303 return _defaultView;
\r
309 /// Gets or sets the expression that will return
\r
310 /// a value used to represent this table in the user interface.
\r
312 [DataCategory ("Data")]
\r
313 [DefaultValue ("")]
\r
314 public string DisplayExpression {
\r
315 get { return _displayExpression == null ? "" : _displayExpression; }
\r
316 set { _displayExpression = value; }
\r
320 /// Gets the collection of customized user information.
\r
322 [Browsable (false)]
\r
323 [DataCategory ("Data")]
\r
324 public PropertyCollection ExtendedProperties {
\r
325 get { return _extendedProperties; }
\r
329 /// Gets a value indicating whether there are errors in
\r
330 /// any of the_rows in any of the tables of the DataSet to
\r
331 /// which the table belongs.
\r
333 [Browsable (false)]
\r
334 public bool HasErrors {
\r
336 // we can not use the _hasError flag because we do not know when to turn it off!
\r
337 for (int i = 0; i < _rows.Count; i++) {
\r
338 if (_rows[i].HasErrors)
\r
346 /// Gets or sets the locale information used to
\r
347 /// compare strings within the table.
\r
349 public CultureInfo Locale {
\r
351 // if the locale is null, we check for the DataSet locale
\r
352 // and if the DataSet is null we return the current culture.
\r
353 // this way if DataSet locale is changed, only if there is no locale for
\r
354 // the DataTable it influece the Locale get;
\r
355 if (_locale != null)
\r
357 if (DataSet != null)
\r
358 return DataSet.Locale;
\r
359 return CultureInfo.CurrentCulture;
\r
362 if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
\r
363 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
365 if (_locale == null || !_locale.Equals(value))
\r
370 internal bool LocaleSpecified {
\r
371 get { return _locale != null; }
\r
375 /// Gets or sets the initial starting size for this table.
\r
377 [DataCategory ("Data")]
\r
378 [DefaultValue (50)]
\r
379 public int MinimumCapacity {
\r
380 get { return _minimumCapacity; }
\r
381 set { _minimumCapacity = value; }
\r
385 /// Gets or sets the namespace for the XML represenation
\r
386 /// of the data stored in the DataTable.
\r
388 [DataCategory ("Data")]
\r
389 public string Namespace {
\r
391 if (_nameSpace != null)
\r
393 if (DataSet != null)
\r
394 return DataSet.Namespace;
\r
395 return String.Empty;
\r
397 set { _nameSpace = value; }
\r
401 /// Gets the collection of parent relations for
\r
402 /// this DataTable.
\r
404 [Browsable (false)]
\r
405 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
406 public DataRelationCollection ParentRelations {
\r
407 get { return _parentRelations; }
\r
411 /// Gets or sets the namespace for the XML represenation
\r
412 /// of the data stored in the DataTable.
\r
414 [DataCategory ("Data")]
\r
415 [DefaultValue ("")]
\r
416 public string Prefix {
\r
417 get { return _prefix == null ? "" : _prefix; }
\r
419 // Prefix cannot contain any special characters other than '_' and ':'
\r
420 for (int i = 0; i < value.Length; i++) {
\r
421 if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
\r
422 throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
\r
429 /// Gets or sets an array of columns that function as
\r
430 /// primary keys for the data table.
\r
432 [DataCategory ("Data")]
\r
433 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
\r
434 [TypeConverterAttribute ("System.Data.PrimaryKeyTypeConverter, " + Consts.AssemblySystem_Data)]
\r
435 public DataColumn[] PrimaryKey {
\r
437 if (_primaryKeyConstraint == null)
\r
438 return new DataColumn[] {};
\r
439 return _primaryKeyConstraint.Columns;
\r
442 if (value == null || value.Length == 0) {
\r
443 if (_primaryKeyConstraint != null) {
\r
444 _primaryKeyConstraint.SetIsPrimaryKey (false);
\r
445 Constraints.Remove(_primaryKeyConstraint);
\r
446 _primaryKeyConstraint = null;
\r
451 if (InitInProgress) {
\r
452 _latestPrimaryKeyCols = value;
\r
456 // first check if value is the same as current PK.
\r
457 if (_primaryKeyConstraint != null &&
\r
458 DataColumn.AreColumnSetsTheSame (value, _primaryKeyConstraint.Columns))
\r
461 //Does constraint exist for these columns
\r
462 UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet (this.Constraints, (DataColumn[]) value);
\r
464 //if constraint doesn't exist for columns
\r
465 //create new unique primary key constraint
\r
467 foreach (DataColumn Col in (DataColumn []) value) {
\r
468 if (Col.Table == null)
\r
471 if (Columns.IndexOf (Col) < 0)
\r
472 throw new ArgumentException ("PrimaryKey columns do not belong to this table.");
\r
474 // create constraint with primary key indication set to false
\r
475 // to avoid recursion
\r
476 uc = new UniqueConstraint ((DataColumn []) value, false);
\r
477 Constraints.Add (uc);
\r
480 //Remove the existing primary key
\r
481 if (_primaryKeyConstraint != null) {
\r
482 _primaryKeyConstraint.SetIsPrimaryKey (false);
\r
483 Constraints.Remove (_primaryKeyConstraint);
\r
484 _primaryKeyConstraint = null;
\r
487 //set the constraint as the new primary key
\r
488 UniqueConstraint.SetAsPrimaryKey (Constraints, uc);
\r
489 _primaryKeyConstraint = uc;
\r
491 for (int j = 0; j < uc.Columns.Length; ++j)
\r
492 uc.Columns [j].AllowDBNull = false;
\r
496 internal UniqueConstraint PrimaryKeyConstraint {
\r
497 get { return _primaryKeyConstraint; }
\r
501 /// Gets the collection of_rows that belong to this table.
\r
503 [Browsable (false)]
\r
504 public DataRowCollection Rows {
\r
505 get { return _rows; }
\r
509 /// Gets or sets an System.ComponentModel.ISite
\r
510 /// for the DataTable.
\r
512 [Browsable (false)]
\r
513 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
514 public override ISite Site {
\r
515 get { return _site; }
\r
516 set { _site = value; }
\r
520 /// Gets or sets the name of the the DataTable.
\r
522 [DataCategory ("Data")]
\r
523 [DefaultValue ("")]
\r
524 [RefreshProperties (RefreshProperties.All)]
\r
525 public string TableName {
\r
526 get { return _tableName == null ? "" : _tableName; }
\r
527 set { _tableName = value; }
\r
530 bool IListSource.ContainsListCollection {
\r
531 // the collection is a DataView
\r
532 get { return false; }
\r
535 internal RecordCache RecordCache {
\r
536 get { return _recordCache; }
\r
539 private DataRowBuilder RowBuilder {
\r
541 // initiate only one row builder.
\r
542 if (_rowBuilder == null)
\r
543 _rowBuilder = new DataRowBuilder (this, -1, 0);
\r
545 // new row get id -1.
\r
546 _rowBuilder._rowId = -1;
\r
548 return _rowBuilder;
\r
552 internal bool EnforceConstraints {
\r
553 get { return enforceConstraints; }
\r
555 if (value == enforceConstraints)
\r
559 // reset indexes since they may be outdated
\r
562 // assert all constraints
\r
563 foreach (Constraint constraint in Constraints)
\r
564 constraint.AssertConstraint ();
\r
566 AssertNotNullConstraints ();
\r
569 Constraint.ThrowConstraintException ();
\r
571 enforceConstraints = value;
\r
575 internal void AssertNotNullConstraints ()
\r
577 if (_duringDataLoad && !_nullConstraintViolationDuringDataLoad)
\r
581 for (int i = 0; i < Columns.Count; i++) {
\r
582 DataColumn column = Columns [i];
\r
583 if (column.AllowDBNull)
\r
585 for (int j = 0; j < Rows.Count; j++) {
\r
586 if (Rows [j].HasVersion (DataRowVersion.Default) && Rows[j].IsNull (column)) {
\r
588 string errMsg = String.Format ("Column '{0}' does not allow DBNull.Value.",
\r
589 column.ColumnName);
\r
590 Rows [j].SetColumnError (i, errMsg);
\r
591 Rows [j].RowError = errMsg;
\r
595 _nullConstraintViolationDuringDataLoad = seen;
\r
598 internal bool RowsExist (DataColumn [] columns, DataColumn [] relatedColumns, DataRow row)
\r
600 int curIndex = row.IndexFromVersion (DataRowVersion.Default);
\r
601 int tmpRecord = RecordCache.NewRecord ();
\r
604 for (int i = 0; i < relatedColumns.Length; i++)
\r
605 // according to MSDN: the DataType value for both columns must be identical.
\r
606 columns [i].DataContainer.CopyValue (relatedColumns [i].DataContainer, curIndex, tmpRecord);
\r
607 return RowsExist (columns, tmpRecord);
\r
609 RecordCache.DisposeRecord (tmpRecord);
\r
613 bool RowsExist (DataColumn [] columns, int index)
\r
615 Index indx = this.FindIndex (columns);
\r
618 return indx.Find (index) != -1;
\r
620 // we have to perform full-table scan
\r
621 // check that there is a parent for this row.
\r
622 foreach (DataRow thisRow in this.Rows) {
\r
623 if (thisRow.RowState == DataRowState.Deleted)
\r
625 // check if the values in the columns are equal
\r
626 int thisIndex = thisRow.IndexFromVersion (
\r
627 thisRow.RowState == DataRowState.Modified ? DataRowVersion.Original : DataRowVersion.Current);
\r
629 foreach (DataColumn column in columns) {
\r
630 if (column.DataContainer.CompareValues (thisIndex, index) != 0) {
\r
642 /// Commits all the changes made to this table since the
\r
643 /// last time AcceptChanges was called.
\r
645 public void AcceptChanges ()
\r
647 //FIXME: Do we need to validate anything here or
\r
648 //try to catch any errors to deal with them?
\r
650 // we do not use foreach because if one of the rows is in Delete state
\r
651 // it will be romeved from Rows and we get an exception.
\r
653 for (int i = 0; i < Rows.Count; ) {
\r
655 myRow.AcceptChanges ();
\r
657 // if the row state is Detached it meens that it was removed from row list (Rows)
\r
658 // so we should not increase 'i'.
\r
659 if (myRow.RowState != DataRowState.Detached)
\r
662 _rows.OnListChanged (this, new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
666 /// Begins the initialization of a DataTable that is used
\r
667 /// on a form or used by another component. The initialization
\r
668 /// occurs at runtime.
\r
674 InitInProgress = true;
\r
675 tableInitialized = false;
\r
679 /// Turns off notifications, index maintenance, and
\r
680 /// constraints while loading data.
\r
682 public void BeginLoadData ()
\r
684 if (this._duringDataLoad)
\r
687 //duringDataLoad is important to EndLoadData and
\r
688 //for not throwing unexpected exceptions.
\r
689 this._duringDataLoad = true;
\r
690 this._nullConstraintViolationDuringDataLoad = false;
\r
692 if (this.dataSet != null) {
\r
693 //Saving old Enforce constraints state for later
\r
694 //use in the EndLoadData.
\r
695 this.dataSetPrevEnforceConstraints = this.dataSet.EnforceConstraints;
\r
696 this.dataSet.EnforceConstraints = false;
\r
698 //if table does not belong to any data set use EnforceConstraints of the table
\r
699 this.EnforceConstraints = false;
\r
705 /// Clears the DataTable of all data.
\r
707 public void Clear ()
\r
709 // Foriegn key constraints are checked in _rows.Clear method
\r
714 /// Clones the structure of the DataTable, including
\r
715 /// all DataTable schemas and constraints.
\r
717 public virtual DataTable Clone ()
\r
719 // Use Activator so we can use non-public constructors.
\r
720 DataTable Copy = (DataTable) Activator.CreateInstance (GetType (), true);
\r
721 CopyProperties (Copy);
\r
726 /// Computes the given expression on the current_rows that
\r
727 /// pass the filter criteria.
\r
729 public object Compute (string expression, string filter)
\r
731 // expression is an aggregate function
\r
732 // filter is an expression used to limit rows
\r
734 DataRow [] rows = Select (filter);
\r
736 if (rows == null || rows.Length == 0)
\r
737 return DBNull.Value;
\r
739 Parser parser = new Parser (rows);
\r
740 IExpression expr = parser.Compile (expression);
\r
741 object obj = expr.Eval (rows [0]);
\r
747 /// Copies both the structure and data for this DataTable.
\r
749 public DataTable Copy ()
\r
751 DataTable copy = Clone ();
\r
753 copy._duringDataLoad = true;
\r
754 foreach (DataRow row in Rows) {
\r
755 DataRow newRow = copy.NewNotInitializedRow ();
\r
756 copy.Rows.AddInternal (newRow);
\r
757 CopyRow (row, newRow);
\r
759 copy._duringDataLoad = false;
\r
761 // rebuild copy indexes after loading all rows
\r
762 copy.ResetIndexes ();
\r
766 internal void CopyRow (DataRow fromRow, DataRow toRow)
\r
768 if (fromRow.HasErrors)
\r
769 fromRow.CopyErrors (toRow);
\r
771 if (fromRow.HasVersion (DataRowVersion.Original))
\r
772 toRow.Original = toRow.Table.RecordCache.CopyRecord (this, fromRow.Original, -1);
\r
774 if (fromRow.HasVersion (DataRowVersion.Current)) {
\r
775 if (fromRow.Original != fromRow.Current)
\r
776 toRow.Current = toRow.Table.RecordCache.CopyRecord (this, fromRow.Current, -1);
\r
778 toRow.Current = toRow.Original;
\r
782 private void CopyProperties (DataTable Copy)
\r
784 Copy.CaseSensitive = CaseSensitive;
\r
785 Copy._virginCaseSensitive = _virginCaseSensitive;
\r
787 // Copy.ChildRelations
\r
788 // Copy.Constraints
\r
790 // Copy.DefaultView
\r
792 Copy.DisplayExpression = DisplayExpression;
\r
793 if (ExtendedProperties.Count > 0) {
\r
794 // Cannot copy extended properties directly as the property does not have a set accessor
\r
795 Array tgtArray = Array.CreateInstance (typeof (object), ExtendedProperties.Count);
\r
796 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
\r
797 for (int i=0; i < ExtendedProperties.Count; i++)
\r
798 Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
\r
800 Copy._locale = _locale;
\r
801 Copy.MinimumCapacity = MinimumCapacity;
\r
802 Copy.Namespace = Namespace;
\r
803 // Copy.ParentRelations
\r
804 Copy.Prefix = Prefix;
\r
806 Copy.TableName = TableName;
\r
808 bool isEmpty = Copy.Columns.Count == 0;
\r
811 foreach (DataColumn column in Columns) {
\r
812 // When cloning a table, the columns may be added in the default constructor.
\r
813 if (isEmpty || !Copy.Columns.Contains (column.ColumnName))
\r
814 Copy.Columns.Add (column.Clone ());
\r
816 foreach (DataColumn column in Copy.Columns)
\r
817 column.CompileExpression ();
\r
819 CopyConstraints (Copy);
\r
820 // add primary key to the copy
\r
821 if (PrimaryKey.Length > 0) {
\r
822 DataColumn[] pColumns = new DataColumn[PrimaryKey.Length];
\r
823 for (int i = 0; i < pColumns.Length; i++)
\r
824 pColumns[i] = Copy.Columns[PrimaryKey[i].ColumnName];
\r
826 Copy.PrimaryKey = pColumns;
\r
830 private void CopyConstraints (DataTable copy)
\r
832 UniqueConstraint origUc;
\r
833 UniqueConstraint copyUc;
\r
834 for (int i = 0; i < this.Constraints.Count; i++) {
\r
835 if (this.Constraints[i] is UniqueConstraint) {
\r
836 // typed ds can already contain the constraints
\r
837 if (copy.Constraints.Contains (this.Constraints [i].ConstraintName))
\r
840 origUc = (UniqueConstraint) this.Constraints [i];
\r
841 DataColumn [] columns = new DataColumn [origUc.Columns.Length];
\r
842 for (int j = 0; j < columns.Length; j++)
\r
843 columns[j] = copy.Columns [origUc.Columns [j].ColumnName];
\r
845 copyUc = new UniqueConstraint (origUc.ConstraintName, columns, origUc.IsPrimaryKey);
\r
846 copy.Constraints.Add (copyUc);
\r
851 /// Ends the initialization of a DataTable that is used
\r
852 /// on a form or used by another component. The
\r
853 /// initialization occurs at runtime.
\r
859 InitInProgress = false;
\r
860 DataTableInitialized ();
\r
864 // defined in NET_2_0 profile
\r
865 partial void DataTableInitialized ();
\r
867 internal bool InitInProgress {
\r
868 get { return fInitInProgress; }
\r
869 set { fInitInProgress = value; }
\r
872 internal void FinishInit ()
\r
874 UniqueConstraint oldPK = _primaryKeyConstraint;
\r
876 // Columns shud be added 'before' the constraints
\r
877 Columns.PostAddRange ();
\r
879 // Add the constraints
\r
880 _constraintCollection.PostAddRange ();
\r
882 // ms.net behavior : If a PrimaryKey (UniqueConstraint) is added thru AddRange,
\r
883 // then it takes precedence over an direct assignment of PrimaryKey
\r
884 if (_primaryKeyConstraint == oldPK)
\r
885 PrimaryKey = _latestPrimaryKeyCols;
\r
889 /// Turns on notifications, index maintenance, and
\r
890 /// constraints after loading data.
\r
892 public void EndLoadData ()
\r
894 if (this._duringDataLoad) {
\r
895 //Getting back to previous EnforceConstraint state
\r
896 if (this.dataSet != null)
\r
897 this.dataSet.InternalEnforceConstraints (this.dataSetPrevEnforceConstraints, true);
\r
899 this.EnforceConstraints = true;
\r
901 this._duringDataLoad = false;
\r
906 /// Gets a copy of the DataTable that contains all
\r
907 /// changes made to it since it was loaded or
\r
908 /// AcceptChanges was last called.
\r
910 public DataTable GetChanges ()
\r
912 return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
\r
916 /// Gets a copy of the DataTable containing all
\r
917 /// changes made to it since it was last loaded, or
\r
918 /// since AcceptChanges was called, filtered by DataRowState.
\r
920 public DataTable GetChanges (DataRowState rowStates)
\r
922 DataTable copyTable = null;
\r
924 foreach (DataRow row in Rows) {
\r
925 // The spec says relationship constraints may cause Unchanged parent rows to be included but
\r
926 // MS .NET 1.1 does not include Unchanged rows even if their child rows are changed.
\r
927 if (!row.IsRowChanged (rowStates))
\r
929 if (copyTable == null)
\r
930 copyTable = Clone ();
\r
931 DataRow newRow = copyTable.NewNotInitializedRow ();
\r
932 // Don't check for ReadOnly, when cloning data to new uninitialized row.
\r
933 row.CopyValuesToRow (newRow, false);
\r
934 newRow.XmlRowID = row.XmlRowID;
\r
935 copyTable.Rows.AddInternal (newRow);
\r
942 /// Gets an array of DataRow objects that contain errors.
\r
944 public DataRow [] GetErrors ()
\r
946 ArrayList errors = new ArrayList();
\r
947 for (int i = 0; i < _rows.Count; i++) {
\r
948 if (_rows[i].HasErrors)
\r
949 errors.Add (_rows[i]);
\r
952 DataRow[] ret = NewRowArray (errors.Count);
\r
953 errors.CopyTo (ret, 0);
\r
958 /// This member is only meant to support Mono's infrastructure
\r
960 protected virtual DataTable CreateInstance ()
\r
962 return Activator.CreateInstance (this.GetType (), true) as DataTable;
\r
966 /// This member is only meant to support Mono's infrastructure
\r
968 protected virtual Type GetRowType ()
\r
970 return typeof (DataRow);
\r
974 /// This member is only meant to support Mono's infrastructure
\r
976 /// Used for Data Binding between System.Web.UI. controls
\r
977 /// like a DataGrid
\r
979 /// System.Windows.Forms controls like a DataGrid
\r
981 IList IListSource.GetList ()
\r
983 IList list = (IList) DefaultView;
\r
988 /// Copies a DataRow into a DataTable, preserving any
\r
989 /// property settings, as well as original and current values.
\r
991 public void ImportRow (DataRow row)
\r
993 if (row.RowState == DataRowState.Detached)
\r
996 DataRow newRow = NewNotInitializedRow ();
\r
999 if (row.HasVersion (DataRowVersion.Original)) {
\r
1000 original = row.IndexFromVersion (DataRowVersion.Original);
\r
1001 newRow.Original = RecordCache.NewRecord ();
\r
1002 RecordCache.CopyRecord (row.Table, original, newRow.Original);
\r
1005 if (row.HasVersion (DataRowVersion.Current)) {
\r
1006 int current = row.IndexFromVersion (DataRowVersion.Current);
\r
1007 if (current == original) {
\r
1008 newRow.Current = newRow.Original;
\r
1010 newRow.Current = RecordCache.NewRecord ();
\r
1011 RecordCache.CopyRecord (row.Table, current, newRow.Current);
\r
1015 //Import the row only if RowState is not detached
\r
1016 //Validation for Deleted Rows happens during Accept/RejectChanges
\r
1017 if (row.RowState != DataRowState.Deleted)
\r
1018 newRow.Validate ();
\r
1020 AddRowToIndexes (newRow);
\r
1021 Rows.AddInternal(newRow);
\r
1023 if (row.HasErrors)
\r
1024 row.CopyErrors (newRow);
\r
1027 internal int DefaultValuesRowIndex {
\r
1028 get { return _defaultValuesRowIndex; }
\r
1032 /// This member is only meant to support Mono's infrastructure
\r
1036 GetObjectData (SerializationInfo info, StreamingContext context)
\r
1038 if (RemotingFormat == SerializationFormat.Xml) {
\r
1040 if (dataSet != null)
\r
1043 dset = new DataSet ("tmpDataSet");
\r
1044 dset.Tables.Add (this);
\r
1047 StringWriter sw = new StringWriter ();
\r
1048 XmlTextWriter tw = new XmlTextWriter (sw);
\r
1049 tw.Formatting = Formatting.Indented;
\r
1050 dset.WriteIndividualTableContent (tw, this, XmlWriteMode.DiffGram);
\r
1053 StringWriter sw2 = new StringWriter ();
\r
1054 DataTableCollection tables = new DataTableCollection (dset);
\r
1055 tables.Add (this);
\r
1056 XmlSchemaWriter.WriteXmlSchema (dset, new XmlTextWriter (sw2), tables, null);
\r
1059 info.AddValue ("XmlSchema", sw2.ToString(), typeof(string));
\r
1060 info.AddValue ("XmlDiffGram", sw.ToString(), typeof(string));
\r
1061 } else /*if (RemotingFormat == SerializationFormat.Binary)*/ {
\r
1062 BinarySerializeProperty (info);
\r
1063 if (dataSet == null) {
\r
1064 for (int i = 0; i < Columns.Count; i++) {
\r
1065 info.AddValue ("DataTable.DataColumn_" + i + ".Expression",
\r
1066 Columns[i].Expression);
\r
1068 BinarySerialize (info, "DataTable_0.");
\r
1074 /// Finds and updates a specific row. If no matching row
\r
1075 /// is found, a new row is created using the given values.
\r
1077 public DataRow LoadDataRow (object [] values, bool fAcceptChanges)
\r
1079 DataRow row = null;
\r
1080 if (PrimaryKey.Length == 0) {
\r
1081 row = Rows.Add (values);
\r
1083 EnsureDefaultValueRowIndex ();
\r
1084 int newRecord = CreateRecord (values);
\r
1085 int existingRecord = _primaryKeyConstraint.Index.Find (newRecord);
\r
1087 if (existingRecord < 0) {
\r
1088 row = NewRowFromBuilder (RowBuilder);
\r
1089 row.Proposed = newRecord;
\r
1090 Rows.AddInternal(row);
\r
1091 if (!_duringDataLoad)
\r
1092 AddRowToIndexes (row);
\r
1094 row = RecordCache [existingRecord];
\r
1096 row.ImportRecord (newRecord);
\r
1101 if (fAcceptChanges)
\r
1102 row.AcceptChanges ();
\r
1107 internal DataRow LoadDataRow (IDataRecord record, int[] mapping, int length, bool fAcceptChanges)
\r
1109 DataRow row = null;
\r
1110 int tmpRecord = this.RecordCache.NewRecord ();
\r
1112 RecordCache.ReadIDataRecord (tmpRecord,record,mapping,length);
\r
1113 if (PrimaryKey.Length != 0) {
\r
1114 bool hasPrimaryValues = true;
\r
1115 foreach(DataColumn col in PrimaryKey) {
\r
1116 if(!(col.Ordinal < mapping.Length)) {
\r
1117 hasPrimaryValues = false;
\r
1122 if (hasPrimaryValues) {
\r
1123 int existingRecord = _primaryKeyConstraint.Index.Find (tmpRecord);
\r
1124 if (existingRecord != -1)
\r
1125 row = RecordCache [existingRecord];
\r
1129 if (row == null) {
\r
1130 row = NewNotInitializedRow ();
\r
1131 row.Proposed = tmpRecord;
\r
1132 Rows.AddInternal (row);
\r
1135 row.ImportRecord (tmpRecord);
\r
1139 if (fAcceptChanges)
\r
1140 row.AcceptChanges ();
\r
1143 this.RecordCache.DisposeRecord (tmpRecord);
\r
1150 /// Creates a new DataRow with the same schema as the table.
\r
1152 public DataRow NewRow ()
\r
1154 EnsureDefaultValueRowIndex();
\r
1156 DataRow newRow = NewRowFromBuilder (RowBuilder);
\r
1157 newRow.Proposed = CreateRecord (null);
\r
1158 NewRowAdded (newRow);
\r
1162 // defined in the NET_2_0 profile
\r
1163 partial void NewRowAdded (DataRow dr);
\r
1165 internal int CreateRecord (object [] values)
\r
1167 int valCount = values != null ? values.Length : 0;
\r
1168 if (valCount > Columns.Count)
\r
1169 throw new ArgumentException ("Input array is longer than the number of columns in this table.");
\r
1171 int index = RecordCache.NewRecord ();
\r
1174 for (int i = 0; i < valCount; i++) {
\r
1175 object value = values[i];
\r
1176 if (value == null)
\r
1177 Columns [i].SetDefaultValue (index);
\r
1179 Columns [i][index] = values [i];
\r
1182 for(int i = valCount; i < Columns.Count; i++)
\r
1183 Columns [i].SetDefaultValue (index);
\r
1187 RecordCache.DisposeRecord (index);
\r
1192 private void EnsureDefaultValueRowIndex ()
\r
1194 // initialize default values row for the first time
\r
1195 if (_defaultValuesRowIndex == -1) {
\r
1196 _defaultValuesRowIndex = RecordCache.NewRecord();
\r
1197 for (int i = 0; i < Columns.Count; ++i) {
\r
1198 DataColumn column = Columns [i];
\r
1199 column.DataContainer [_defaultValuesRowIndex] = column.DefaultValue;
\r
1205 /// This member supports the .NET Framework infrastructure
\r
1206 /// and is not intended to be used directly from your code.
\r
1208 DataRow [] empty_rows;
\r
1209 protected internal DataRow [] NewRowArray (int size)
\r
1211 if (size == 0 && empty_rows != null)
\r
1212 return empty_rows;
\r
1213 Type t = GetRowType ();
\r
1214 /* Avoid reflection if possible */
\r
1215 DataRow [] rows = t == typeof (DataRow) ? new DataRow [size] : (DataRow []) Array.CreateInstance (t, size);
\r
1217 empty_rows = rows;
\r
1222 /// Creates a new row from an existing row.
\r
1224 protected virtual DataRow NewRowFromBuilder (DataRowBuilder builder)
\r
1226 return new DataRow (builder);
\r
1229 internal DataRow NewNotInitializedRow ()
\r
1231 EnsureDefaultValueRowIndex ();
\r
1233 return NewRowFromBuilder (RowBuilder);
\r
1237 /// Rolls back all changes that have been made to the
\r
1238 /// table since it was loaded, or the last time AcceptChanges
\r
1241 public void RejectChanges ()
\r
1243 for (int i = _rows.Count - 1; i >= 0; i--) {
\r
1244 DataRow row = _rows [i];
\r
1245 if (row.RowState != DataRowState.Unchanged)
\r
1246 _rows [i].RejectChanges ();
\r
1251 /// Resets the DataTable to its original state.
\r
1253 public virtual void Reset ()
\r
1256 while (ParentRelations.Count > 0) {
\r
1257 if (dataSet.Relations.Contains (ParentRelations [ParentRelations.Count - 1].RelationName))
\r
1258 dataSet.Relations.Remove (ParentRelations [ParentRelations.Count - 1]);
\r
1261 while (ChildRelations.Count > 0) {
\r
1262 if (dataSet.Relations.Contains (ChildRelations [ChildRelations.Count - 1].RelationName))
\r
1263 dataSet.Relations.Remove (ChildRelations [ChildRelations.Count - 1]);
\r
1265 Constraints.Clear ();
\r
1270 /// Gets an array of all DataRow objects.
\r
1272 public DataRow[] Select ()
\r
1274 return Select (String.Empty, String.Empty, DataViewRowState.CurrentRows);
\r
1278 /// Gets an array of all DataRow objects that match
\r
1279 /// the filter criteria in order of primary key (or
\r
1280 /// lacking one, order of addition.)
\r
1282 public DataRow[] Select (string filterExpression)
\r
1284 return Select (filterExpression, String.Empty, DataViewRowState.CurrentRows);
\r
1288 /// Gets an array of all DataRow objects that
\r
1289 /// match the filter criteria, in the the
\r
1290 /// specified sort order.
\r
1292 public DataRow[] Select (string filterExpression, string sort)
\r
1294 return Select (filterExpression, sort, DataViewRowState.CurrentRows);
\r
1298 /// Gets an array of all DataRow objects that match
\r
1299 /// the filter in the order of the sort, that match
\r
1300 /// the specified state.
\r
1302 public DataRow [] Select (string filterExpression, string sort, DataViewRowState recordStates)
\r
1304 if (filterExpression == null)
\r
1305 filterExpression = String.Empty;
\r
1307 IExpression filter = null;
\r
1308 if (filterExpression != String.Empty) {
\r
1309 Parser parser = new Parser ();
\r
1310 filter = parser.Compile (filterExpression);
\r
1313 DataColumn [] columns = _emptyColumnArray;
\r
1314 ListSortDirection [] sorts = null;
\r
1316 if (sort != null && !sort.Equals(String.Empty))
\r
1317 columns = ParseSortString (this, sort, out sorts, false);
\r
1319 if (Rows.Count == 0)
\r
1320 return NewRowArray (0);
\r
1322 //if sort order is not given, sort it in Ascending order of the
\r
1323 //columns involved in the filter
\r
1324 if (columns.Length == 0 && filter != null) {
\r
1325 ArrayList list = new ArrayList ();
\r
1326 for (int i = 0; i < Columns.Count; ++i) {
\r
1327 if (!filter.DependsOn (Columns [i]))
\r
1329 list.Add (Columns [i]);
\r
1331 columns = (DataColumn []) list.ToArray (typeof (DataColumn));
\r
1334 bool addIndex = true;
\r
1335 if (filterExpression != String.Empty)
\r
1337 Index index = GetIndex (columns, sorts, recordStates, filter, false, addIndex);
\r
1339 int [] records = index.GetAll ();
\r
1340 DataRow [] dataRows = NewRowArray (index.Size);
\r
1341 for (int i = 0; i < dataRows.Length; i++)
\r
1342 dataRows [i] = RecordCache [records [i]];
\r
1347 private void AddIndex (Index index)
\r
1349 if (_indexes == null)
\r
1350 _indexes = new ArrayList();
\r
1351 _indexes.Add (index);
\r
1355 /// Returns index corresponding to columns,sort,row state filter and unique values given.
\r
1356 /// If such an index not exists, creates a new one.
\r
1358 /// <param name="columns">Columns set of the index to look for.</param>
\r
1359 /// <param name="sort">Columns sort order of the index to look for.</param>
\r
1360 /// <param name="rowState">Rpw state filter of the index to look for.</param>
\r
1361 /// <param name="unique">Uniqueness of the index to look for.</param>
\r
1362 /// <param name="strict">Indicates whenever the index found should correspond in its uniquness to the value of unique parameter specified.</param>
\r
1363 /// <param name="reset">Indicates whenever the already existing index should be forced to reset.</param>
\r
1364 /// <returns></returns>
\r
1365 internal Index GetIndex (DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter, bool reset)
\r
1367 return GetIndex (columns, sort, rowState, filter, reset, true);
\r
1370 internal Index GetIndex (DataColumn[] columns, ListSortDirection[] sort,
\r
1371 DataViewRowState rowState, IExpression filter,
\r
1372 bool reset, bool addIndex)
\r
1374 Index index = FindIndex(columns, sort, rowState, filter);
\r
1375 if (index == null) {
\r
1376 index = new Index(new Key (this, columns, sort, rowState, filter));
\r
1380 } else if (reset) {
\r
1381 // reset existing index only if asked for this
\r
1387 internal Index FindIndex (DataColumn[] columns)
\r
1389 return FindIndex (columns, null, DataViewRowState.None, null);
\r
1392 internal Index FindIndex (DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter)
\r
1394 if (Indexes != null) {
\r
1395 foreach (Index index in Indexes) {
\r
1396 if (index.Key.Equals (columns,sort,rowState, filter))
\r
1403 internal void ResetIndexes ()
\r
1405 foreach(Index index in Indexes)
\r
1409 internal void ResetCaseSensitiveIndexes ()
\r
1411 foreach (Index index in Indexes) {
\r
1412 bool containsStringcolumns = false;
\r
1413 foreach(DataColumn column in index.Key.Columns) {
\r
1414 if (column.DataType == typeof(string)) {
\r
1415 containsStringcolumns = true;
\r
1420 if (!containsStringcolumns && index.Key.HasFilter) {
\r
1421 foreach (DataColumn column in Columns) {
\r
1422 if ((column.DataType == DbTypes.TypeOfString) && (index.Key.DependsOn (column))) {
\r
1423 containsStringcolumns = true;
\r
1429 if (containsStringcolumns)
\r
1434 internal void DropIndex (Index index)
\r
1436 if (index != null && index.RefCount == 0) {
\r
1437 _indexes.Remove (index);
\r
1441 internal void DropReferencedIndexes (DataColumn column)
\r
1443 if (_indexes != null)
\r
1444 for (int i = _indexes.Count - 1; i >= 0; i--) {
\r
1445 Index indx = (Index)_indexes [i];
\r
1446 if (indx.Key.DependsOn (column))
\r
1447 _indexes.Remove (indx);
\r
1451 internal void AddRowToIndexes (DataRow row)
\r
1453 if (_indexes != null) {
\r
1454 for (int i = 0; i < _indexes.Count; ++i)
\r
1455 ((Index)_indexes [i]).Add (row);
\r
1459 internal void DeleteRowFromIndexes (DataRow row)
\r
1461 if (_indexes != null) {
\r
1462 foreach (Index indx in _indexes)
\r
1463 indx.Delete (row);
\r
1468 /// Gets the TableName and DisplayExpression, if
\r
1469 /// there is one as a concatenated string.
\r
1471 public override string ToString ()
\r
1473 //LAMESPEC: spec says concat the two. impl puts a
\r
1474 //plus sign infront of DisplayExpression
\r
1475 string retVal = TableName;
\r
1476 if(DisplayExpression != null && DisplayExpression != "")
\r
1477 retVal += " + " + DisplayExpression;
\r
1484 /// Raises the ColumnChanged event.
\r
1486 protected virtual void OnColumnChanged (DataColumnChangeEventArgs e)
\r
1488 if (null != ColumnChanged)
\r
1489 ColumnChanged (this, e);
\r
1492 internal void RaiseOnColumnChanged (DataColumnChangeEventArgs e)
\r
1494 OnColumnChanged (e);
\r
1498 /// Raises the ColumnChanging event.
\r
1500 protected virtual void OnColumnChanging (DataColumnChangeEventArgs e)
\r
1502 if (null != ColumnChanging)
\r
1503 ColumnChanging (this, e);
\r
1506 internal void RaiseOnColumnChanging (DataColumnChangeEventArgs e)
\r
1508 OnColumnChanging(e);
\r
1512 /// Raises the PropertyChanging event.
\r
1515 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
\r
1517 //if (null != PropertyChanging)
\r
1519 // PropertyChanging (this, pcevent);
\r
1521 throw new NotImplementedException ();
\r
1525 /// Notifies the DataTable that a DataColumn is being removed.
\r
1527 protected internal virtual void OnRemoveColumn (DataColumn column)
\r
1529 DropReferencedIndexes (column);
\r
1533 /// Raises the RowChanged event.
\r
1535 protected virtual void OnRowChanged (DataRowChangeEventArgs e)
\r
1537 if (null != RowChanged)
\r
1538 RowChanged (this, e);
\r
1543 /// Raises the RowChanging event.
\r
1545 protected virtual void OnRowChanging (DataRowChangeEventArgs e)
\r
1547 if (null != RowChanging)
\r
1548 RowChanging (this, e);
\r
1552 /// Raises the RowDeleted event.
\r
1554 protected virtual void OnRowDeleted (DataRowChangeEventArgs e)
\r
1556 if (null != RowDeleted)
\r
1557 RowDeleted (this, e);
\r
1561 /// Raises the RowDeleting event.
\r
1563 protected virtual void OnRowDeleting (DataRowChangeEventArgs e)
\r
1565 if (null != RowDeleting)
\r
1566 RowDeleting (this, e);
\r
1570 /// Occurs when after a value has been changed for
\r
1571 /// the specified DataColumn in a DataRow.
\r
1573 [DataCategory ("Data")]
\r
1574 public event DataColumnChangeEventHandler ColumnChanged;
\r
1577 /// Occurs when a value is being changed for the specified
\r
1578 /// DataColumn in a DataRow.
\r
1580 [DataCategory ("Data")]
\r
1581 public event DataColumnChangeEventHandler ColumnChanging;
\r
1584 /// Occurs after a DataRow has been changed successfully.
\r
1586 [DataCategory ("Data")]
\r
1587 public event DataRowChangeEventHandler RowChanged;
\r
1590 /// Occurs when a DataRow is changing.
\r
1592 [DataCategory ("Data")]
\r
1593 public event DataRowChangeEventHandler RowChanging;
\r
1596 /// Occurs after a row in the table has been deleted.
\r
1598 [DataCategory ("Data")]
\r
1599 public event DataRowChangeEventHandler RowDeleted;
\r
1602 /// Occurs before a row in the table is about to be deleted.
\r
1604 [DataCategory ("Data")]
\r
1605 public event DataRowChangeEventHandler RowDeleting;
\r
1607 #endregion // Events
\r
1609 internal static DataColumn[] ParseSortString (DataTable table, string sort, out ListSortDirection[] sortDirections, bool rejectNoResult)
\r
1611 DataColumn[] sortColumns = _emptyColumnArray;
\r
1612 sortDirections = null;
\r
1614 ArrayList columns = null;
\r
1615 ArrayList sorts = null;
\r
1617 if (sort != null && !sort.Equals ("")) {
\r
1618 columns = new ArrayList ();
\r
1619 sorts = new ArrayList();
\r
1620 string[] columnExpression = sort.Trim ().Split (new char[1] {','});
\r
1622 for (int c = 0; c < columnExpression.Length; c++) {
\r
1623 string rawColumnName = columnExpression[c].Trim ();
\r
1625 Match match = SortRegex.Match (rawColumnName);
\r
1626 Group g = match.Groups["ColName"] ;
\r
1628 throw new IndexOutOfRangeException ("Could not find column: " + rawColumnName);
\r
1630 string columnName = g.Value;
\r
1631 DataColumn dc = table.Columns[columnName];
\r
1634 dc = table.Columns[Int32.Parse (columnName)];
\r
1635 } catch (FormatException) {
\r
1636 throw new IndexOutOfRangeException("Cannot find column " + columnName);
\r
1641 g = match.Groups["Order"];
\r
1642 if (!g.Success || String.Compare (g.Value, "ASC", true, CultureInfo.InvariantCulture) == 0)
\r
1643 sorts.Add(ListSortDirection.Ascending);
\r
1645 sorts.Add (ListSortDirection.Descending);
\r
1648 sortColumns = (DataColumn[]) columns.ToArray (typeof (DataColumn));
\r
1649 sortDirections = new ListSortDirection[sorts.Count];
\r
1650 for (int i = 0; i < sortDirections.Length; i++)
\r
1651 sortDirections[i] = (ListSortDirection)sorts[i];
\r
1654 if (rejectNoResult) {
\r
1655 if (sortColumns == null)
\r
1656 throw new SystemException ("sort expression result is null");
\r
1657 if (sortColumns.Length == 0)
\r
1658 throw new SystemException("sort expression result is 0");
\r
1661 return sortColumns;
\r
1664 private void UpdatePropertyDescriptorsCache ()
\r
1666 PropertyDescriptor[] descriptors = new PropertyDescriptor[Columns.Count + ChildRelations.Count];
\r
1668 foreach (DataColumn col in Columns)
\r
1669 descriptors [index++] = new DataColumnPropertyDescriptor (col);
\r
1671 foreach (DataRelation rel in ChildRelations)
\r
1672 descriptors [index++] = new DataRelationPropertyDescriptor (rel);
\r
1674 _propertyDescriptorsCache = new PropertyDescriptorCollection (descriptors);
\r
1677 internal PropertyDescriptorCollection GetPropertyDescriptorCollection()
\r
1679 if (_propertyDescriptorsCache == null)
\r
1680 UpdatePropertyDescriptorsCache ();
\r
1681 return _propertyDescriptorsCache;
\r
1684 internal void ResetPropertyDescriptorsCache ()
\r
1686 _propertyDescriptorsCache = null;
\r
1689 internal void SetRowsID()
\r
1691 int dataRowID = 0;
\r
1692 foreach (DataRow row in Rows) {
\r
1693 row.XmlRowID = dataRowID;
\r
1699 [XmlSchemaProvider ("GetDataTableSchema")]
\r
1700 partial class DataTable : IXmlSerializable {
\r
1701 [MonoNotSupported ("")]
\r
1702 XmlSchema IXmlSerializable.GetSchema ()
\r
1704 return GetSchema ();
\r
1707 void IXmlSerializable.ReadXml (XmlReader reader)
\r
1709 ReadXml_internal (reader, true);
\r
1712 void IXmlSerializable.WriteXml (XmlWriter writer)
\r
1714 DataSet dset = dataSet;
\r
1715 bool isPartOfDataSet = true;
\r
1717 if (dataSet == null) {
\r
1718 dset = new DataSet ();
\r
1719 dset.Tables.Add (this);
\r
1720 isPartOfDataSet = false;
\r
1723 XmlSchemaWriter.WriteXmlSchema (writer, new DataTable [] { this },
\r
1724 null, TableName, dset.DataSetName, LocaleSpecified ? Locale : dset.LocaleSpecified ? dset.Locale : null);
\r
1725 dset.WriteIndividualTableContent (writer, this, XmlWriteMode.DiffGram);
\r
1728 if (!isPartOfDataSet)
\r
1729 dataSet.Tables.Remove(this);
\r
1733 protected virtual XmlSchema GetSchema ()
\r
1735 throw new NotImplementedException ();
\r
1738 public static XmlSchemaComplexType GetDataTableSchema (XmlSchemaSet schemaSet)
\r
1740 return new XmlSchemaComplexType ();
\r
1743 public XmlReadMode ReadXml (Stream stream)
\r
1745 return ReadXml (new XmlTextReader(stream, new NameTable ()));
\r
1748 public XmlReadMode ReadXml (string fileName)
\r
1750 XmlReader reader = new XmlTextReader (fileName);
\r
1752 return ReadXml (reader);
\r
1758 public XmlReadMode ReadXml (TextReader reader)
\r
1760 return ReadXml (new XmlTextReader (reader));
\r
1763 public XmlReadMode ReadXml (XmlReader reader)
\r
1765 return ReadXml_internal (reader, false);
\r
1768 public XmlReadMode ReadXml_internal (XmlReader reader, bool serializable)
\r
1770 // The documentation from MS for this method is rather
\r
1771 // poor. The following cases have been observed
\r
1772 // during testing:
\r
1774 // Reading a table from XML may create a DataSet to
\r
1775 // store child tables.
\r
1777 // If the table has at least one column present,
\r
1778 // we do not require the schema to be present in
\r
1779 // the xml. If the table has no columns, neither
\r
1780 // regular data nor diffgrams will be read, but
\r
1781 // will throw an error indicating that schema
\r
1782 // will not be inferred.
\r
1784 // We will likely need to take advantage of the
\r
1785 // msdata:MainDataTable attribute added to the
\r
1786 // schema info to load into the appropriate
\r
1788 bool isPartOfDataSet = true;
\r
1789 bool isTableNameBlank = false;
\r
1790 XmlReadMode mode = XmlReadMode.ReadSchema;
\r
1791 DataSet dataSet = null;
\r
1792 DataSet ds = new DataSet ();
\r
1794 reader.MoveToContent ();
\r
1795 if (Columns.Count > 0 && reader.LocalName != "diffgram" || serializable)
\r
1796 mode = ds.ReadXml (reader);
\r
1797 else if (Columns.Count > 0 && reader.LocalName == "diffgram") {
\r
1799 if (TableName == String.Empty)
\r
1800 isTableNameBlank = true;
\r
1801 if (DataSet == null) {
\r
1802 isPartOfDataSet = false;
\r
1803 ds.Tables.Add (this);
\r
1804 mode = ds.ReadXml (reader);
\r
1806 mode = DataSet.ReadXml (reader);
\r
1807 } catch (DataException) {
\r
1808 mode = XmlReadMode.DiffGram;
\r
1809 if (isTableNameBlank)
\r
1810 TableName = String.Empty;
\r
1812 if (!isPartOfDataSet)
\r
1813 ds.Tables.Remove (this);
\r
1817 mode = ds.ReadXml (reader, XmlReadMode.ReadSchema);
\r
1819 if (mode == XmlReadMode.InferSchema)
\r
1820 mode = XmlReadMode.IgnoreSchema;
\r
1821 if (DataSet == null) {
\r
1822 isPartOfDataSet = false;
\r
1823 dataSet = new DataSet ();
\r
1824 if (TableName == String.Empty)
\r
1825 isTableNameBlank = true;
\r
1826 dataSet.Tables.Add (this);
\r
1829 DenyXmlResolving (this, ds, mode, isTableNameBlank, isPartOfDataSet);
\r
1830 if (Columns.Count > 0 && TableName != ds.Tables [0].TableName) {
\r
1831 if (isPartOfDataSet == false)
\r
1832 dataSet.Tables.Remove (this);
\r
1834 if (isTableNameBlank && isPartOfDataSet == false)
\r
1835 TableName = String.Empty;
\r
1839 TableName = ds.Tables [0].TableName;
\r
1842 if (!isPartOfDataSet) {
\r
1843 if (Columns.Count > 0) {
\r
1844 dataSet.Merge (ds, true, MissingSchemaAction.Ignore);
\r
1846 dataSet.Merge (ds, true, MissingSchemaAction.AddWithKey);
\r
1848 if (ChildRelations.Count == 0) {
\r
1849 dataSet.Tables.Remove (this);
\r
1851 dataSet.DataSetName = ds.DataSetName;
\r
1854 if (Columns.Count > 0) {
\r
1855 DataSet.Merge (ds, true, MissingSchemaAction.Ignore);
\r
1857 DataSet.Merge (ds, true, MissingSchemaAction.AddWithKey);
\r
1863 private void DenyXmlResolving (DataTable table, DataSet ds, XmlReadMode mode, bool isTableNameBlank, bool isPartOfDataSet)
\r
1865 if (ds.Tables.Count == 0 && table.Columns.Count == 0)
\r
1866 throw new InvalidOperationException ("DataTable does not support schema inference from XML");
\r
1868 if (table.Columns.Count == 0 && ds.Tables [0].TableName != table.TableName && isTableNameBlank == false)
\r
1869 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
\r
1870 table.TableName));
\r
1872 if (table.Columns.Count > 0 && ds.Tables [0].TableName != table.TableName &&
\r
1873 isTableNameBlank == false && mode == XmlReadMode.ReadSchema &&
\r
1874 isPartOfDataSet == false)
\r
1875 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
\r
1876 table.TableName));
\r
1878 if (isPartOfDataSet == true && table.Columns.Count > 0 &&
\r
1879 mode == XmlReadMode.ReadSchema && table.TableName != ds.Tables [0].TableName)
\r
1880 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
\r
1881 table.TableName));
\r
1884 public void ReadXmlSchema (Stream stream)
\r
1886 ReadXmlSchema (new XmlTextReader (stream));
\r
1889 public void ReadXmlSchema (TextReader reader)
\r
1891 ReadXmlSchema (new XmlTextReader (reader));
\r
1894 public void ReadXmlSchema (string fileName)
\r
1896 XmlTextReader reader = null;
\r
1898 reader = new XmlTextReader (fileName);
\r
1899 ReadXmlSchema (reader);
\r
1901 if (reader != null)
\r
1906 private bool ReadSchemaElement (XmlReader reader)
\r
1908 var insideElement = false;
\r
1909 reader.MoveToElement ();
\r
1910 while (reader.Read ())
\r
1912 if (reader.NodeType == XmlNodeType.Element || reader.NodeType == XmlNodeType.EndElement)
\r
1914 if (reader.NamespaceURI != XmlSchema.Namespace)
\r
1916 if (reader.LocalName == "schema" || insideElement)
\r
1917 throw new ArgumentException ("The schema namespace is invalid. Please use this one instead: " + XmlSchema.Namespace);
\r
1919 insideElement = true;
\r
1920 reader.MoveToElement ();
\r
1931 public void ReadXmlSchema (XmlReader reader)
\r
1933 if (this.Columns.Count > 0)
\r
1936 DataSet ds = new DataSet ();
\r
1938 if (reader.ReadState == ReadState.Initial && !ReadSchemaElement (reader))
\r
1941 new XmlSchemaDataImporter (ds, reader, false).Process ();
\r
1942 DataTable target = null;
\r
1943 if (TableName == String.Empty) {
\r
1944 if (ds.Tables.Count > 0)
\r
1945 target = ds.Tables [0];
\r
1948 target = ds.Tables [TableName];
\r
1949 if (target == null)
\r
1950 throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source.", TableName));
\r
1952 if (target != null)
\r
1953 target.CopyProperties (this);
\r
1956 [MonoNotSupported ("")]
\r
1957 protected virtual void ReadXmlSerializable (XmlReader reader)
\r
1959 throw new NotImplementedException ();
\r
1962 private XmlWriterSettings GetWriterSettings ()
\r
1964 XmlWriterSettings s = new XmlWriterSettings ();
\r
1966 s.OmitXmlDeclaration = true;
\r
1970 public void WriteXml (Stream stream)
\r
1972 WriteXml (stream, XmlWriteMode.IgnoreSchema, false);
\r
1975 public void WriteXml (TextWriter writer)
\r
1977 WriteXml (writer, XmlWriteMode.IgnoreSchema, false);
\r
1980 public void WriteXml (XmlWriter writer)
\r
1982 WriteXml (writer, XmlWriteMode.IgnoreSchema, false);
\r
1985 public void WriteXml (string fileName)
\r
1987 WriteXml (fileName, XmlWriteMode.IgnoreSchema, false);
\r
1990 public void WriteXml (Stream stream, XmlWriteMode mode)
\r
1992 WriteXml (stream, mode, false);
\r
1995 public void WriteXml (TextWriter writer, XmlWriteMode mode)
\r
1997 WriteXml (writer, mode, false);
\r
2000 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
\r
2002 WriteXml (writer, mode, false);
\r
2005 public void WriteXml (string fileName, XmlWriteMode mode)
\r
2007 WriteXml (fileName, mode, false);
\r
2010 public void WriteXml (Stream stream, bool writeHierarchy)
\r
2012 WriteXml (stream, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2015 public void WriteXml (string fileName, bool writeHierarchy)
\r
2017 WriteXml (fileName, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2020 public void WriteXml (TextWriter writer, bool writeHierarchy)
\r
2022 WriteXml (writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2025 public void WriteXml (XmlWriter writer, bool writeHierarchy)
\r
2027 WriteXml (writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
\r
2030 public void WriteXml (Stream stream, XmlWriteMode mode, bool writeHierarchy)
\r
2032 WriteXml (XmlWriter.Create (stream, GetWriterSettings ()), mode, writeHierarchy);
\r
2035 public void WriteXml (string fileName, XmlWriteMode mode, bool writeHierarchy)
\r
2037 XmlWriter xw = null;
\r
2039 xw = XmlWriter.Create (fileName, GetWriterSettings ());
\r
2040 WriteXml (xw, mode, writeHierarchy);
\r
2047 public void WriteXml (TextWriter writer, XmlWriteMode mode, bool writeHierarchy)
\r
2049 WriteXml (XmlWriter.Create (writer, GetWriterSettings ()), mode, writeHierarchy);
\r
2052 public void WriteXml (XmlWriter writer, XmlWriteMode mode, bool writeHierarchy)
\r
2054 // If we're in mode XmlWriteMode.WriteSchema, we need to output an extra
\r
2055 // msdata:MainDataTable attribute that wouldn't normally be part of the
\r
2056 // DataSet WriteXml output.
\r
2058 // For the writeHierarchy == true case, we write what would be output by
\r
2059 // a DataSet write, but we limit ourselves to our table and its descendants.
\r
2061 // For the writeHierarchy == false case, we write what would be output by
\r
2062 // a DataSet write, but we limit ourselves to this table.
\r
2064 // If the table is not in a DataSet, we follow the following behaviour:
\r
2065 // For WriteSchema cases, we do a write as if there is a wrapper
\r
2066 // dataset called NewDataSet.
\r
2067 // For IgnoreSchema or DiffGram cases, we do a write as if there
\r
2068 // is a wrapper dataset called DocumentElement.
\r
2070 // Generate a list of tables to write.
\r
2071 List <DataTable> tables = new List <DataTable> ();
\r
2072 if (writeHierarchy == false)
\r
2073 tables.Add (this);
\r
2075 FindAllChildren (tables, this);
\r
2077 // If we're in a DataSet, generate a list of relations to write.
\r
2078 List <DataRelation> relations = new List <DataRelation> ();
\r
2079 if (DataSet != null) {
\r
2080 foreach (DataRelation relation in DataSet.Relations) {
\r
2081 if (tables.Contains (relation.ParentTable) &&
\r
2082 tables.Contains (relation.ChildTable))
\r
2083 relations.Add (relation);
\r
2087 // Add the msdata:MainDataTable info if we're writing schema data.
\r
2088 string mainDataTable = null;
\r
2089 if (mode == XmlWriteMode.WriteSchema)
\r
2090 mainDataTable = this.TableName;
\r
2092 // Figure out the DataSet name.
\r
2093 string dataSetName = null;
\r
2094 if (DataSet != null)
\r
2095 dataSetName = DataSet.DataSetName;
\r
2096 else if (DataSet == null && mode == XmlWriteMode.WriteSchema)
\r
2097 dataSetName = "NewDataSet";
\r
2099 dataSetName = "DocumentElement";
\r
2101 XmlTableWriter.WriteTables(writer, mode, tables, relations, mainDataTable, dataSetName);
\r
2104 private void FindAllChildren(List<DataTable> list, DataTable root)
\r
2106 if (!list.Contains(root))
\r
2109 foreach (DataRelation relation in root.ChildRelations)
\r
2111 FindAllChildren(list, relation.ChildTable);
\r
2116 public void WriteXmlSchema (Stream stream)
\r
2118 if (TableName == "") {
\r
2119 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2121 XmlWriterSettings s = GetWriterSettings ();
\r
2122 s.OmitXmlDeclaration = false;
\r
2123 WriteXmlSchema (XmlWriter.Create (stream, s));
\r
2126 public void WriteXmlSchema (TextWriter writer)
\r
2128 if (TableName == "") {
\r
2129 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2131 XmlWriterSettings s = GetWriterSettings ();
\r
2132 s.OmitXmlDeclaration = false;
\r
2133 WriteXmlSchema (XmlWriter.Create (writer, s));
\r
2136 public void WriteXmlSchema (XmlWriter writer)
\r
2138 WriteXmlSchema (writer, false);
\r
2140 if (TableName == "") {
\r
2141 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2143 DataSet ds = DataSet;
\r
2144 DataSet tmp = null;
\r
2147 tmp = ds = new DataSet ();
\r
2148 ds.Tables.Add (this);
\r
2150 writer.WriteStartDocument ();
\r
2151 DataTableCollection col = new DataTableCollection (ds);
\r
2153 DataTable [] tables = new DataTable [col.Count];
\r
2154 for (int i = 0; i < col.Count; i++) tables[i] = col[i];
\r
2156 if (ds.Namespace == "")
\r
2157 tableName = TableName;
\r
2159 tableName = ds.Namespace + "_x003A_" + TableName;
\r
2160 XmlSchemaWriter.WriteXmlSchema (writer, tables, null, tableName, ds.DataSetName);
\r
2163 ds.Tables.Remove (this);
\r
2168 public void WriteXmlSchema (string fileName)
\r
2170 if (fileName == "") {
\r
2171 throw new ArgumentException ("Empty path name is not legal.");
\r
2173 if (TableName == "") {
\r
2174 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2176 XmlTextWriter writer = null;
\r
2178 XmlWriterSettings s = GetWriterSettings ();
\r
2179 s.OmitXmlDeclaration = false;
\r
2180 writer = new XmlTextWriter (fileName, null);
\r
2181 WriteXmlSchema (writer);
\r
2183 if (writer != null) {
\r
2189 public void WriteXmlSchema (Stream stream, bool writeHierarchy)
\r
2191 if (TableName == "") {
\r
2192 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2194 XmlWriterSettings s = GetWriterSettings ();
\r
2195 s.OmitXmlDeclaration = false;
\r
2196 WriteXmlSchema (XmlWriter.Create (stream, s), writeHierarchy);
\r
2199 public void WriteXmlSchema (TextWriter writer, bool writeHierarchy)
\r
2201 if (TableName == "") {
\r
2202 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2204 XmlWriterSettings s = GetWriterSettings ();
\r
2205 s.OmitXmlDeclaration = false;
\r
2206 WriteXmlSchema (XmlWriter.Create (writer, s), writeHierarchy);
\r
2209 public void WriteXmlSchema (XmlWriter writer, bool writeHierarchy)
\r
2211 if (TableName == "") {
\r
2212 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2214 // if (writeHierarchy == false) {
\r
2215 // WriteXmlSchema (writer);
\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 //XmlSchemaWriter.WriteXmlSchema (ds, writer);
\r
2227 //DataTable [] tables = new DataTable [ds.Tables.Count];
\r
2228 DataTable [] tables = null;
\r
2229 //DataRelation [] relations = new DataRelation [ds.Relations.Count];
\r
2230 //for (int i = 0; i < ds.Relations.Count; i++) {
\r
2231 // relations[i] = ds.Relations[i];
\r
2233 DataRelation [] relations = null;
\r
2234 if (writeHierarchy && ChildRelations.Count > 0) {
\r
2235 relations = new DataRelation [ChildRelations.Count];
\r
2236 for (int i = 0; i < ChildRelations.Count; i++) {
\r
2237 relations [i] = ChildRelations [i];
\r
2239 tables = new DataTable [ds.Tables.Count];
\r
2240 for (int i = 0; i < ds.Tables.Count; i++) tables [i] = ds.Tables [i];
\r
2242 tables = new DataTable [1];
\r
2243 tables [0] = this;
\r
2247 if (ds.Namespace == "")
\r
2248 tableName = TableName;
\r
2250 tableName = ds.Namespace + "_x003A_" + TableName;
\r
2251 XmlSchemaWriter.WriteXmlSchema (writer, tables, relations, tableName, ds.DataSetName, LocaleSpecified ? Locale : ds.LocaleSpecified ? ds.Locale : null);
\r
2254 ds.Tables.Remove (this);
\r
2259 public void WriteXmlSchema (string fileName, bool writeHierarchy)
\r
2261 if (fileName == "") {
\r
2262 throw new ArgumentException ("Empty path name is not legal.");
\r
2264 if (TableName == "") {
\r
2265 throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
\r
2267 XmlTextWriter writer = null;
\r
2269 XmlWriterSettings s = GetWriterSettings ();
\r
2270 s.OmitXmlDeclaration = false;
\r
2271 writer = new XmlTextWriter (fileName, null);
\r
2272 WriteXmlSchema (writer, writeHierarchy);
\r
2274 if (writer != null) {
\r
2281 partial class DataTable : ISupportInitializeNotification {
\r
2282 private bool tableInitialized = true;
\r
2284 [Browsable (false)]
\r
2285 public bool IsInitialized {
\r
2286 get { return tableInitialized; }
\r
2289 public event EventHandler Initialized;
\r
2291 private void OnTableInitialized (EventArgs e)
\r
2293 if (null != Initialized)
\r
2294 Initialized (this, e);
\r
2297 partial void DataTableInitialized ()
\r
2299 tableInitialized = true;
\r
2300 OnTableInitialized (new EventArgs ());
\r
2304 partial class DataTable {
\r
2305 public DataTable (string tableName, string tableNamespace)
\r
2306 : this (tableName)
\r
2308 _nameSpace = tableNamespace;
\r
2311 SerializationFormat remotingFormat = SerializationFormat.Xml;
\r
2312 [DefaultValue (SerializationFormat.Xml)]
\r
2313 public SerializationFormat RemotingFormat {
\r
2315 if (dataSet != null)
\r
2316 remotingFormat = dataSet.RemotingFormat;
\r
2317 return remotingFormat;
\r
2320 if (dataSet != null)
\r
2321 throw new ArgumentException ("Cannot have different remoting format property value for DataSet and DataTable");
\r
2322 remotingFormat = value;
\r
2326 internal void DeserializeConstraints (ArrayList arrayList)
\r
2328 bool fKeyNavigate = false;
\r
2329 for (int i = 0; i < arrayList.Count; i++) {
\r
2330 ArrayList tmpArrayList = arrayList [i] as ArrayList;
\r
2331 if (tmpArrayList == null)
\r
2333 if ((string) tmpArrayList [0] == "F") {
\r
2334 int [] constraintsArray = tmpArrayList [2] as int [];
\r
2336 if (constraintsArray == null)
\r
2338 ArrayList parentColumns = new ArrayList ();
\r
2339 DataTable dt = dataSet.Tables [constraintsArray [0]];
\r
2340 for (int j = 0; j < constraintsArray.Length - 1; j++) {
\r
2341 parentColumns.Add (dt.Columns [constraintsArray [j + 1]]);
\r
2344 constraintsArray = tmpArrayList [3] as int [];
\r
2346 if (constraintsArray == null)
\r
2348 ArrayList childColumns = new ArrayList ();
\r
2349 dt = dataSet.Tables [constraintsArray [0]];
\r
2350 for (int j = 0; j < constraintsArray.Length - 1; j++) {
\r
2351 childColumns.Add (dt.Columns [constraintsArray [j + 1]]);
\r
2354 ForeignKeyConstraint fKeyConstraint = new
\r
2355 ForeignKeyConstraint ((string) tmpArrayList [1],
\r
2356 (DataColumn []) parentColumns.ToArray (typeof (DataColumn)),
\r
2357 (DataColumn []) childColumns.ToArray (typeof (DataColumn)));
\r
2358 Array ruleArray = (Array) tmpArrayList [4];
\r
2359 fKeyConstraint.AcceptRejectRule = (AcceptRejectRule) ruleArray.GetValue (0);
\r
2360 fKeyConstraint.UpdateRule = (Rule) ruleArray.GetValue (1);
\r
2361 fKeyConstraint.DeleteRule = (Rule) ruleArray.GetValue (2);
\r
2362 // FIXME: refactor this deserialization code out to ForeighKeyConstraint
\r
2363 fKeyConstraint.SetExtendedProperties ((PropertyCollection) tmpArrayList [5]);
\r
2364 Constraints.Add (fKeyConstraint);
\r
2365 fKeyNavigate = true;
\r
2366 } else if (fKeyNavigate == false &&
\r
2367 (string) tmpArrayList [0] == "U") {
\r
2368 UniqueConstraint unique = null;
\r
2369 ArrayList uniqueDataColumns = new ArrayList ();
\r
2370 int [] constraintsArray = tmpArrayList [2] as int [];
\r
2372 if (constraintsArray == null)
\r
2375 for (int j = 0; j < constraintsArray.Length; j++) {
\r
2376 uniqueDataColumns.Add (Columns [constraintsArray [j]]);
\r
2378 unique = new UniqueConstraint ((string) tmpArrayList[1],
\r
2379 (DataColumn[]) uniqueDataColumns.
\r
2380 ToArray (typeof (DataColumn)),
\r
2381 (bool) tmpArrayList [3]);
\r
2383 If UniqueConstraint already exist, don't add them
\r
2385 if (Constraints.IndexOf (unique) != -1 ||
\r
2386 Constraints.IndexOf ((string) tmpArrayList[1]) != -1) {
\r
2389 // FIXME: refactor this deserialization code out to UniqueConstraint
\r
2390 unique.SetExtendedProperties ((PropertyCollection) tmpArrayList [4]);
\r
2391 Constraints.Add (unique);
\r
2393 fKeyNavigate = false;
\r
2398 DataRowState GetCurrentRowState (BitArray rowStateBitArray, int i)
\r
2400 DataRowState currentRowState;
\r
2401 if (rowStateBitArray[i] == false &&
\r
2402 rowStateBitArray[i+1] == false &&
\r
2403 rowStateBitArray[i+2] == true)
\r
2404 currentRowState = DataRowState.Detached;
\r
2405 else if (rowStateBitArray[i] == false &&
\r
2406 rowStateBitArray[i+1] == false &&
\r
2407 rowStateBitArray[i+2] == false)
\r
2408 currentRowState = DataRowState.Unchanged;
\r
2409 else if (rowStateBitArray[i] == false &&
\r
2410 rowStateBitArray[i+1] == true &&
\r
2411 rowStateBitArray[i+2] == false)
\r
2412 currentRowState = DataRowState.Added;
\r
2413 else if (rowStateBitArray[i] == true &&
\r
2414 rowStateBitArray[i+1] == true &&
\r
2415 rowStateBitArray[i+2] == false)
\r
2416 currentRowState = DataRowState.Deleted;
\r
2418 currentRowState = DataRowState.Modified;
\r
2419 return currentRowState;
\r
2422 internal void DeserializeRecords (ArrayList arrayList, ArrayList nullBits, BitArray rowStateBitArray)
\r
2424 BitArray nullBit = null;
\r
2425 if (arrayList == null || arrayList.Count < 1)
\r
2427 int len = ((Array) arrayList [0]).Length;
\r
2428 object [] tmpArray = new object [arrayList.Count];
\r
2430 DataRowState currentRowState;
\r
2431 for (int l = 0; l < len; l++) { // Columns
\r
2432 currentRowState = GetCurrentRowState (rowStateBitArray, k *3);
\r
2433 for (int j = 0; j < arrayList.Count; j++) { // Rows
\r
2434 Array array = (Array) arrayList [j];
\r
2435 nullBit = (BitArray) nullBits [j];
\r
2436 if (nullBit [l] == false) {
\r
2437 tmpArray [j] = array.GetValue (l);
\r
2439 tmpArray [j] = null;
\r
2442 LoadDataRow (tmpArray, false);
\r
2443 if (currentRowState == DataRowState.Modified) {
\r
2444 Rows[k].AcceptChanges ();
\r
2446 for (int j = 0; j < arrayList.Count; j++) {
\r
2447 Array array = (Array) arrayList [j];
\r
2448 nullBit = (BitArray) nullBits[j];
\r
2449 if (nullBit [l] == false) {
\r
2450 Rows [k][j] = array.GetValue (l);
\r
2452 Rows [k][j] = null;
\r
2455 } else if (currentRowState == DataRowState.Unchanged) {
\r
2456 Rows[k].AcceptChanges ();
\r
2457 } else if (currentRowState == DataRowState.Deleted) {
\r
2458 Rows[k].AcceptChanges ();
\r
2459 Rows[k].Delete ();
\r
2465 void BinaryDeserializeTable (SerializationInfo info)
\r
2467 ArrayList arrayList = null;
\r
2469 TableName = info.GetString ("DataTable.TableName");
\r
2470 Namespace = info.GetString ("DataTable.Namespace");
\r
2471 Prefix = info.GetString ("DataTable.Prefix");
\r
2472 CaseSensitive = info.GetBoolean ("DataTable.CaseSensitive");
\r
2474 FIXME: Private variable available in SerializationInfo
\r
2475 this.caseSensitiveAmbientCaseSensitive = info.GetBoolean("DataTable.caseSensitiveAmbientCaseSensitive");
\r
2476 this.NestedInDataSet = info.GetBoolean("DataTable.NestedInDataSet");
\r
2477 this.RepeatableElement = info.GetBoolean("DataTable.RepeatableElement");
\r
2478 this.RemotingVersion = (System.Version) info.GetValue("DataTable.RemotingVersion",
\r
2479 typeof(System.Version));
\r
2481 Locale = new CultureInfo (info.GetInt32 ("DataTable.LocaleLCID"));
\r
2482 _extendedProperties = (PropertyCollection) info.GetValue ("DataTable.ExtendedProperties",
\r
2483 typeof (PropertyCollection));
\r
2484 MinimumCapacity = info.GetInt32 ("DataTable.MinimumCapacity");
\r
2485 int columnsCount = info.GetInt32 ("DataTable.Columns.Count");
\r
2487 for (int i = 0; i < columnsCount; i++) {
\r
2489 string prefix = "DataTable.DataColumn_" + i + ".";
\r
2490 Columns[i].ColumnName = info.GetString (prefix + "ColumnName");
\r
2491 Columns[i].Namespace = info.GetString (prefix + "Namespace");
\r
2492 Columns[i].Caption = info.GetString (prefix + "Caption");
\r
2493 Columns[i].Prefix = info.GetString (prefix + "Prefix");
\r
2494 Columns[i].DataType = (Type) info.GetValue (prefix + "DataType",
\r
2496 Columns[i].DefaultValue = info.GetValue (prefix + "DefaultValue",
\r
2498 Columns[i].AllowDBNull = info.GetBoolean (prefix + "AllowDBNull");
\r
2499 Columns[i].AutoIncrement = info.GetBoolean (prefix + "AutoIncrement");
\r
2500 Columns[i].AutoIncrementStep = info.GetInt64 (prefix + "AutoIncrementStep");
\r
2501 Columns[i].AutoIncrementSeed = info.GetInt64(prefix + "AutoIncrementSeed");
\r
2502 Columns[i].ReadOnly = info.GetBoolean (prefix + "ReadOnly");
\r
2503 Columns[i].MaxLength = info.GetInt32 (prefix + "MaxLength");
\r
2505 FIXME: Private variable available in SerializationInfo
\r
2506 this.Columns[i].SimpleType = info.GetString("DataTable.DataColumn_" +
\r
2507 i + ".SimpleType");
\r
2508 this.Columns[i].AutoIncrementCurrent = info.GetInt64("DataTable.DataColumn_" +
\r
2509 i + ".AutoIncrementCurrent");
\r
2510 this.Columns[i].XmlDataType = info.GetString("DataTable.DataColumn_" +
\r
2511 i + ".XmlDataType");
\r
2513 Columns[i].ExtendedProperties = (PropertyCollection) info.GetValue (prefix + "ExtendedProperties",
\r
2514 typeof (PropertyCollection));
\r
2515 if (Columns[i].DataType == typeof (DataSetDateTime)) {
\r
2516 Columns[i].DateTimeMode = (DataSetDateTime) info.GetValue (prefix + "DateTimeMode",
\r
2517 typeof (DataSetDateTime));
\r
2519 Columns[i].ColumnMapping = (MappingType) info.GetValue (prefix + "ColumnMapping",
\r
2520 typeof (MappingType));
\r
2522 Columns[i].Expression = info.GetString (prefix + "Expression");
\r
2524 prefix = "DataTable_0.";
\r
2526 arrayList = (ArrayList) info.GetValue (prefix + "Constraints",
\r
2527 typeof (ArrayList));
\r
2528 if (Constraints == null)
\r
2529 Constraints = new ConstraintCollection (this);
\r
2530 DeserializeConstraints (arrayList);
\r
2531 } catch (SerializationException) {
\r
2535 String prefix = "DataTable_0.";
\r
2536 ArrayList nullBits = (ArrayList) info.GetValue (prefix + "NullBits",
\r
2537 typeof (ArrayList));
\r
2538 arrayList = (ArrayList) info.GetValue (prefix + "Records",
\r
2539 typeof (ArrayList));
\r
2540 BitArray rowStateBitArray = (BitArray) info.GetValue (prefix + "RowStates",
\r
2541 typeof (BitArray));
\r
2542 Hashtable htRowErrors = (Hashtable) info.GetValue (prefix + "RowErrors",
\r
2543 typeof (Hashtable));
\r
2544 DeserializeRecords (arrayList, nullBits, rowStateBitArray);
\r
2545 } catch (SerializationException) {
\r
2549 internal void BinarySerializeProperty (SerializationInfo info)
\r
2551 Version vr = new Version (2, 0);
\r
2552 info.AddValue ("DataTable.RemotingVersion", vr);
\r
2553 info.AddValue ("DataTable.RemotingFormat", RemotingFormat);
\r
2554 info.AddValue ("DataTable.TableName", TableName);
\r
2555 info.AddValue ("DataTable.Namespace", Namespace);
\r
2556 info.AddValue ("DataTable.Prefix", Prefix);
\r
2557 info.AddValue ("DataTable.CaseSensitive", CaseSensitive);
\r
2559 FIXME: Required by MS.NET
\r
2560 caseSensitiveAmbient, NestedInDataSet, RepeatableElement
\r
2562 info.AddValue ("DataTable.caseSensitiveAmbient", true);
\r
2563 info.AddValue ("DataTable.NestedInDataSet", true);
\r
2564 info.AddValue ("DataTable.RepeatableElement", false);
\r
2565 info.AddValue ("DataTable.LocaleLCID", Locale.LCID);
\r
2566 info.AddValue ("DataTable.MinimumCapacity", MinimumCapacity);
\r
2567 info.AddValue ("DataTable.Columns.Count", Columns.Count);
\r
2568 info.AddValue ("DataTable.ExtendedProperties", _extendedProperties);
\r
2569 for (int i = 0; i < Columns.Count; i++) {
\r
2570 info.AddValue ("DataTable.DataColumn_" + i + ".ColumnName",
\r
2571 Columns[i].ColumnName);
\r
2572 info.AddValue ("DataTable.DataColumn_" + i + ".Namespace",
\r
2573 Columns[i].Namespace);
\r
2574 info.AddValue ("DataTable.DataColumn_" + i + ".Caption",
\r
2575 Columns[i].Caption);
\r
2576 info.AddValue ("DataTable.DataColumn_" + i + ".Prefix",
\r
2577 Columns[i].Prefix);
\r
2578 info.AddValue ("DataTable.DataColumn_" + i + ".DataType",
\r
2579 Columns[i].DataType, typeof (Type));
\r
2580 info.AddValue ("DataTable.DataColumn_" + i + ".DefaultValue",
\r
2581 Columns[i].DefaultValue);
\r
2582 info.AddValue ("DataTable.DataColumn_" + i + ".AllowDBNull",
\r
2583 Columns[i].AllowDBNull);
\r
2584 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrement",
\r
2585 Columns[i].AutoIncrement);
\r
2586 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementStep",
\r
2587 Columns[i].AutoIncrementStep);
\r
2588 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementSeed",
\r
2589 Columns[i].AutoIncrementSeed);
\r
2590 info.AddValue ("DataTable.DataColumn_" + i + ".ReadOnly",
\r
2591 Columns[i].ReadOnly);
\r
2592 info.AddValue ("DataTable.DataColumn_" + i + ".MaxLength",
\r
2593 Columns[i].MaxLength);
\r
2594 info.AddValue ("DataTable.DataColumn_" + i + ".ExtendedProperties",
\r
2595 Columns[i].ExtendedProperties);
\r
2596 info.AddValue ("DataTable.DataColumn_" + i + ".DateTimeMode",
\r
2597 Columns[i].DateTimeMode);
\r
2598 info.AddValue ("DataTable.DataColumn_" + i + ".ColumnMapping",
\r
2599 Columns[i].ColumnMapping, typeof (MappingType));
\r
2601 FIXME: Required by MS.NET
\r
2602 SimpleType, AutoIncrementCurrent, XmlDataType
\r
2604 info.AddValue ("DataTable.DataColumn_" + i + ".SimpleType",
\r
2605 null, typeof (string));
\r
2606 info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementCurrent",
\r
2607 Columns[i].AutoIncrementValue());
\r
2608 info.AddValue ("DataTable.DataColumn_" + i + ".XmlDataType",
\r
2609 null, typeof (string));
\r
2612 FIXME: Required by MS.NET
\r
2615 info.AddValue ("DataTable.TypeName", null, typeof (string));
\r
2618 internal void SerializeConstraints (SerializationInfo info, string prefix)
\r
2620 ArrayList constraintArrayList = new ArrayList ();
\r
2621 for (int j = 0; j < Constraints.Count; j++) {
\r
2622 ArrayList constraintList = new ArrayList ();
\r
2623 if (Constraints[j] is UniqueConstraint) {
\r
2624 constraintList.Add ("U");
\r
2625 UniqueConstraint unique = (UniqueConstraint) Constraints [j];
\r
2626 constraintList.Add (unique.ConstraintName);
\r
2627 DataColumn [] columns = unique.Columns;
\r
2628 int [] tmpArray = new int [columns.Length];
\r
2629 for (int k = 0; k < columns.Length; k++)
\r
2630 tmpArray [k] = unique.Table.Columns.IndexOf (unique.Columns [k]);
\r
2631 constraintList.Add (tmpArray);
\r
2632 constraintList.Add (unique.IsPrimaryKey);
\r
2633 constraintList.Add (unique.ExtendedProperties);
\r
2634 } else if (Constraints[j] is ForeignKeyConstraint) {
\r
2635 constraintList.Add ("F");
\r
2636 ForeignKeyConstraint fKey = (ForeignKeyConstraint) Constraints [j];
\r
2637 constraintList.Add (fKey.ConstraintName);
\r
2639 int [] tmpArray = new int [fKey.RelatedColumns.Length + 1];
\r
2640 tmpArray [0] = DataSet.Tables.IndexOf (fKey.RelatedTable);
\r
2641 for (int i = 0; i < fKey.Columns.Length; i++) {
\r
2642 tmpArray [i + 1] = fKey.RelatedColumns [i].Ordinal;
\r
2644 constraintList.Add (tmpArray);
\r
2646 tmpArray = new int [fKey.Columns.Length + 1];
\r
2647 tmpArray [0] = DataSet.Tables.IndexOf (fKey.Table);
\r
2648 for (int i = 0; i < fKey.Columns.Length; i++) {
\r
2649 tmpArray [i + 1] = fKey.Columns [i].Ordinal;
\r
2651 constraintList.Add (tmpArray);
\r
2653 tmpArray = new int [3];
\r
2654 tmpArray [0] = (int) fKey.AcceptRejectRule;
\r
2655 tmpArray [1] = (int) fKey.UpdateRule;
\r
2656 tmpArray [2] = (int) fKey.DeleteRule;
\r
2657 constraintList.Add (tmpArray);
\r
2659 constraintList.Add (fKey.ExtendedProperties);
\r
2663 constraintArrayList.Add (constraintList);
\r
2665 info.AddValue (prefix, constraintArrayList, typeof (ArrayList));
\r
2668 internal void BinarySerialize (SerializationInfo info, string prefix)
\r
2670 int columnsCount = Columns.Count;
\r
2671 int rowsCount = Rows.Count;
\r
2672 int recordsCount = Rows.Count;
\r
2673 ArrayList recordList = new ArrayList ();
\r
2674 ArrayList bitArrayList = new ArrayList ();
\r
2675 BitArray rowStateBitArray = new BitArray (rowsCount * 3);
\r
2676 for (int k = 0; k < Rows.Count; k++) {
\r
2677 if (Rows[k].RowState == DataRowState.Modified)
\r
2680 SerializeConstraints (info, prefix + "Constraints");
\r
2681 for (int j = 0; j < columnsCount; j++) {
\r
2682 if (rowsCount == 0)
\r
2684 BitArray nullBits = new BitArray (rowsCount);
\r
2685 DataColumn column = Columns [j];
\r
2686 Array recordArray = Array.CreateInstance (column.DataType, recordsCount);
\r
2687 for (int k = 0, l = 0; k < Rows.Count; k++, l++) {
\r
2688 DataRowVersion version;
\r
2689 DataRow dr = Rows[k];
\r
2690 if (dr.RowState == DataRowState.Modified) {
\r
2691 version = DataRowVersion.Default;
\r
2692 nullBits.Length = nullBits.Length + 1;
\r
2693 if (dr.IsNull (column, version) == false) {
\r
2694 nullBits [l] = false;
\r
2695 recordArray.SetValue (dr [j, version], l);
\r
2697 nullBits [l] = true;
\r
2700 version = DataRowVersion.Current;
\r
2701 } else if (dr.RowState == DataRowState.Deleted) {
\r
2702 version = DataRowVersion.Original;
\r
2704 version = DataRowVersion.Default;
\r
2706 if (dr.IsNull (column, version) == false) {
\r
2707 nullBits [l] = false;
\r
2708 recordArray.SetValue (dr [j, version], l);
\r
2710 nullBits [l] = true;
\r
2713 recordList.Add (recordArray);
\r
2714 bitArrayList.Add (nullBits);
\r
2716 for (int j = 0; j < Rows.Count; j++) {
\r
2718 DataRowState rowState = Rows [j].RowState;
\r
2719 if (rowState == DataRowState.Detached) {
\r
2720 rowStateBitArray [l] = false;
\r
2721 rowStateBitArray [l + 1] = false;
\r
2722 rowStateBitArray [l + 2] = true;
\r
2723 } else if (rowState == DataRowState.Unchanged) {
\r
2724 rowStateBitArray [l] = false;
\r
2725 rowStateBitArray [l + 1] = false;
\r
2726 rowStateBitArray [l + 2] = false;
\r
2727 } else if (rowState == DataRowState.Added) {
\r
2728 rowStateBitArray [l] = false;
\r
2729 rowStateBitArray [l + 1] = true;
\r
2730 rowStateBitArray [l + 2] = false;
\r
2731 } else if (rowState == DataRowState.Deleted) {
\r
2732 rowStateBitArray [l] = true;
\r
2733 rowStateBitArray [l + 1] = true;
\r
2734 rowStateBitArray [l + 2] = false;
\r
2736 rowStateBitArray [l] = true;
\r
2737 rowStateBitArray [l + 1] = false;
\r
2738 rowStateBitArray [l + 2] = false;
\r
2741 info.AddValue (prefix + "Rows.Count", Rows.Count);
\r
2742 info.AddValue (prefix + "Records.Count", recordsCount);
\r
2743 info.AddValue (prefix + "Records", recordList, typeof (ArrayList));
\r
2744 info.AddValue (prefix + "NullBits", bitArrayList, typeof (ArrayList));
\r
2745 info.AddValue (prefix + "RowStates",
\r
2746 rowStateBitArray, typeof (BitArray));
\r
2747 // FIXME: To get row errors
\r
2748 Hashtable htRowErrors = new Hashtable ();
\r
2749 info.AddValue (prefix + "RowErrors",
\r
2750 htRowErrors, typeof (Hashtable));
\r
2751 // FIXME: To get column errors
\r
2752 Hashtable htColumnErrors = new Hashtable ();
\r
2753 info.AddValue (prefix + "ColumnErrors",
\r
2754 htColumnErrors, typeof (Hashtable));
\r
2757 public DataTableReader CreateDataReader ()
\r
2759 return new DataTableReader (this);
\r
2763 /// Loads the table with the values from the reader
\r
2765 public void Load (IDataReader reader)
\r
2767 if (reader == null)
\r
2768 throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
\r
2769 Load (reader, LoadOption.PreserveChanges);
\r
2773 /// Loads the table with the values from the reader and the pattern
\r
2774 /// of the changes to the existing rows or the new rows are based on
\r
2775 /// the LoadOption passed.
\r
2777 public void Load (IDataReader reader, LoadOption loadOption)
\r
2779 if (reader == null)
\r
2780 throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
\r
2781 bool prevEnforceConstr = this.EnforceConstraints;
\r
2783 this.EnforceConstraints = false;
\r
2784 int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped,
\r
2785 MissingSchemaAction.AddWithKey,
\r
2786 MissingMappingAction.Passthrough,
\r
2787 new DataTableMappingCollection ());
\r
2788 DbDataAdapter.FillFromReader (this,
\r
2795 this.EnforceConstraints = prevEnforceConstr;
\r
2799 public virtual void Load (IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler)
\r
2801 if (reader == null)
\r
2802 throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
\r
2804 bool prevEnforceConstr = this.EnforceConstraints;
\r
2806 this.EnforceConstraints = false;
\r
2808 int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped,
\r
2809 MissingSchemaAction.AddWithKey,
\r
2810 MissingMappingAction.Passthrough,
\r
2811 new DataTableMappingCollection ());
\r
2812 DbDataAdapter.FillFromReader (this,
\r
2820 this.EnforceConstraints = prevEnforceConstr;
\r
2825 /// Loads the given values into an existing row if matches or creates
\r
2826 /// the new row popluated with the values.
\r
2829 /// This method searches for the values using primary keys and it first
\r
2830 /// searches using the original values of the rows and if not found, it
\r
2831 /// searches using the current version of the row.
\r
2833 public DataRow LoadDataRow (object [] values, LoadOption loadOption)
\r
2835 DataRow row = null;
\r
2837 // Find Data DataRow
\r
2838 if (this.PrimaryKey.Length > 0) {
\r
2839 object [] keys = new object [PrimaryKey.Length];
\r
2840 for (int i = 0; i < PrimaryKey.Length; i++)
\r
2841 keys [i] = values [PrimaryKey [i].Ordinal];
\r
2843 row = Rows.Find (keys, DataViewRowState.OriginalRows);
\r
2845 row = Rows.Find (keys);
\r
2848 // If not found, add new row
\r
2849 if (row == null ||
\r
2850 (row.RowState == DataRowState.Deleted && loadOption == LoadOption.Upsert)) {
\r
2851 row = NewNotInitializedRow ();
\r
2852 row.ImportRecord (CreateRecord (values));
\r
2854 row.Validate (); // this adds to index ;-)
\r
2856 if (loadOption == LoadOption.OverwriteChanges ||
\r
2857 loadOption == LoadOption.PreserveChanges)
\r
2858 Rows.AddInternal (row, DataRowAction.ChangeCurrentAndOriginal);
\r
2860 Rows.AddInternal(row);
\r
2864 row.Load (values, loadOption);
\r
2869 public void Merge (DataTable table)
\r
2871 Merge (table, false, MissingSchemaAction.Add);
\r
2874 public void Merge (DataTable table, bool preserveChanges)
\r
2876 Merge (table, preserveChanges, MissingSchemaAction.Add);
\r
2879 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
\r
2881 MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
\r
2884 internal int CompareRecords (int x, int y)
\r
2886 for (int col = 0; col < Columns.Count; col++) {
\r
2887 int res = Columns[col].DataContainer.CompareValues (x, y);
\r
2896 /// Occurs after the Clear method is called on the datatable.
\r
2898 [DataCategory ("Data")]
\r
2899 public event DataTableClearEventHandler TableCleared;
\r
2901 [DataCategory ("Data")]
\r
2902 public event DataTableClearEventHandler TableClearing;
\r
2904 public event DataTableNewRowEventHandler TableNewRow;
\r
2907 /// Raises TableCleared Event and delegates to subscribers
\r
2909 protected virtual void OnTableCleared (DataTableClearEventArgs e)
\r
2911 if (TableCleared != null)
\r
2912 TableCleared (this, e);
\r
2915 internal void DataTableCleared ()
\r
2917 OnTableCleared (new DataTableClearEventArgs (this));
\r
2920 protected virtual void OnTableClearing (DataTableClearEventArgs e)
\r
2922 if (TableClearing != null)
\r
2923 TableClearing (this, e);
\r
2926 internal void DataTableClearing ()
\r
2928 OnTableClearing (new DataTableClearEventArgs (this));
\r
2931 protected virtual void OnTableNewRow (DataTableNewRowEventArgs e)
\r
2933 if (null != TableNewRow)
\r
2934 TableNewRow (this, e);
\r
2937 partial void NewRowAdded (DataRow dr)
\r
2939 OnTableNewRow (new DataTableNewRowEventArgs (dr));
\r