2 // System.Data.DataRow.cs
5 // Rodrigo Moya <rodrigo@ximian.com>
6 // Daniel Morgan <danmorg@sc.rr.com>
7 // Tim Coleman <tim@timcoleman.com>
8 // Ville Palo <vi64pa@koti.soon.fi>
9 // Alan Tam Siu Lung <Tam@SiuLung.com>
11 // (C) Ximian, Inc 2002
12 // (C) Daniel Morgan 2002, 2003
13 // Copyright (C) 2002 Tim Coleman
17 using System.Collections;
18 using System.Globalization;
20 namespace System.Data {
22 /// Represents a row of data in a DataTable.
29 private DataTable _table;
31 private object[] original;
32 private object[] proposed;
33 private object[] current;
35 private string[] columnErrors;
36 private string rowError;
37 private DataRowState rowState;
38 internal int xmlRowID = 0;
39 internal bool _nullConstraintViolation;
40 private string _nullConstraintMessage;
41 private bool editing = false;
42 private bool _hasParentCollection;
43 private bool _inChangingEvent;
50 /// This member supports the .NET Framework infrastructure and is not intended to be
51 /// used directly from your code.
53 protected internal DataRow (DataRowBuilder builder)
55 _table = builder.Table;
59 proposed = new object[_table.Columns.Count];
60 for (int c = 0; c < _table.Columns.Count; c++)
62 proposed[c] = DBNull.Value;
65 columnErrors = new string[_table.Columns.Count];
66 rowError = String.Empty;
68 //on first creating a DataRow it is always detached.
69 rowState = DataRowState.Detached;
71 foreach (DataColumn Col in _table.Columns) {
73 if (Col.AutoIncrement) {
74 this [Col] = Col.AutoIncrementValue();
77 _table.Columns.CollectionChanged += new System.ComponentModel.CollectionChangeEventHandler(CollectionChanged);
86 /// Gets a value indicating whether there are errors in a row.
88 public bool HasErrors {
91 if (RowError != string.Empty)
94 for (int i= 0; i < columnErrors.Length; i++){
95 if (columnErrors[i] != null && columnErrors[i] != string.Empty)
104 /// Gets or sets the data stored in the column specified by name.
106 public object this[string columnName] {
107 get { return this[columnName, DataRowVersion.Default]; }
109 int columnIndex = _table.Columns.IndexOf (columnName);
110 if (columnIndex == -1)
111 throw new IndexOutOfRangeException ();
112 this[columnIndex] = value;
117 /// Gets or sets the data stored in specified DataColumn
119 public object this[DataColumn column] {
122 return this[column, DataRowVersion.Default];}
124 int columnIndex = _table.Columns.IndexOf (column);
125 if (columnIndex == -1)
126 throw new ArgumentException ("The column does not belong to this table.");
127 this[columnIndex] = value;
132 /// Gets or sets the data stored in column specified by index.
134 public object this[int columnIndex] {
135 get { return this[columnIndex, DataRowVersion.Default]; }
137 if (columnIndex < 0 || columnIndex > _table.Columns.Count)
138 throw new IndexOutOfRangeException ();
139 if (rowState == DataRowState.Deleted)
140 throw new DeletedRowInaccessibleException ();
141 DataColumn column = _table.Columns[columnIndex];
142 _table.ChangingDataColumn (this, column, value);
145 bool orginalEditing = editing;
146 if (!orginalEditing) BeginEdit ();
147 object v = SetColumnValue (value, columnIndex);
148 proposed[columnIndex] = v;
149 _table.ChangedDataColumn (this, column, v);
150 if (!orginalEditing) EndEdit ();
155 /// Gets the specified version of data stored in the named column.
157 public object this[string columnName, DataRowVersion version] {
159 int columnIndex = _table.Columns.IndexOf (columnName);
160 if (columnIndex == -1)
161 throw new IndexOutOfRangeException ();
162 return this[columnIndex, version];
167 /// Gets the specified version of data stored in the specified DataColumn.
169 public object this[DataColumn column, DataRowVersion version] {
171 int columnIndex = _table.Columns.IndexOf (column);
172 if (columnIndex == -1)
173 throw new ArgumentException ("The column does not belong to this table.");
174 return this[columnIndex, version];
179 /// Gets the data stored in the column, specified by index and version of the data to
182 public object this[int columnIndex, DataRowVersion version] {
184 if (columnIndex < 0 || columnIndex > _table.Columns.Count)
185 throw new IndexOutOfRangeException ();
186 // Accessing deleted rows
187 if (rowState == DataRowState.Deleted && version != DataRowVersion.Original)
188 throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
190 //if (rowState == DataRowState.Detached && version == DataRowVersion.Default)
191 // throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
192 // Non-existent version
193 //if (!HasVersion (version))
194 // throw new VersionNotFoundException (Locale.GetText ("There is no " + version.ToString () + " data to access."));
195 if (HasVersion(version))
199 case DataRowVersion.Default:
200 if (editing || rowState == DataRowState.Detached)
201 return proposed[columnIndex];
202 return current[columnIndex];
203 case DataRowVersion.Proposed:
204 return proposed[columnIndex];
205 case DataRowVersion.Current:
206 return current[columnIndex];
207 case DataRowVersion.Original:
208 return original[columnIndex];
210 throw new ArgumentException ();
213 if (rowState == DataRowState.Detached && version == DataRowVersion.Default && proposed == null)
214 throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
216 throw new VersionNotFoundException (Locale.GetText ("There is no " + version.ToString () + " data to access."));
221 /// Gets or sets all of the values for this row through an array.
224 public object[] ItemArray {
227 if (rowState == DataRowState.Detached)
228 throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
229 // Accessing deleted rows
230 if (rowState == DataRowState.Deleted)
231 throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
236 if (value.Length > _table.Columns.Count)
237 throw new ArgumentException ();
239 if (rowState == DataRowState.Deleted)
240 throw new DeletedRowInaccessibleException ();
242 object[] newItems = new object[_table.Columns.Count];
244 for (int i = 0; i < _table.Columns.Count; i++) {
246 if (i < value.Length)
251 newItems[i] = SetColumnValue (v, i);
254 bool orginalEditing = editing;
255 if (!orginalEditing) BeginEdit ();
257 if (!orginalEditing) EndEdit ();
261 private object SetColumnValue (object v, int index)
263 object newval = null;
264 DataColumn col = _table.Columns[index];
266 if (_hasParentCollection && col.ReadOnly && v != this[index])
267 throw new ReadOnlyException ();
271 if(col.DefaultValue != DBNull.Value)
273 newval = col.DefaultValue;
275 else if(col.AutoIncrement == true)
277 newval = this [index];
281 if (!col.AllowDBNull)
283 //Constraint violations during data load is raise in DataTable EndLoad
284 this._nullConstraintViolation = true;
285 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
288 newval = DBNull.Value;
291 else if (v == DBNull.Value)
294 if (!col.AllowDBNull)
296 //Constraint violations during data load is raise in DataTable EndLoad
297 this._nullConstraintViolation = true;
298 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
301 newval = DBNull.Value;
305 Type vType = v.GetType(); // data type of value
306 Type cType = col.DataType; // column data type
309 TypeCode typeCode = Type.GetTypeCode(cType);
311 case TypeCode.Boolean :
312 v = Convert.ToBoolean (v);
315 v = Convert.ToByte (v);
318 v = Convert.ToChar (v);
320 case TypeCode.DateTime :
321 v = Convert.ToDateTime (v);
323 case TypeCode.Decimal :
324 v = Convert.ToDecimal (v);
326 case TypeCode.Double :
327 v = Convert.ToDouble (v);
329 case TypeCode.Int16 :
330 v = Convert.ToInt16 (v);
332 case TypeCode.Int32 :
333 v = Convert.ToInt32 (v);
335 case TypeCode.Int64 :
336 v = Convert.ToInt64 (v);
338 case TypeCode.SByte :
339 v = Convert.ToSByte (v);
341 case TypeCode.Single :
342 v = Convert.ToSingle (v);
344 case TypeCode.String :
345 v = Convert.ToString (v);
347 case TypeCode.UInt16 :
348 v = Convert.ToUInt16 (v);
350 case TypeCode.UInt32 :
351 v = Convert.ToUInt32 (v);
353 case TypeCode.UInt64 :
354 v = Convert.ToUInt64 (v);
358 switch(cType.ToString()) {
359 case "System.TimeSpan" :
360 v = (System.TimeSpan) v;
365 case "System.Object" :
366 //v = (System.Object) v;
370 throw new InvalidCastException("Type not supported.");
378 if(col.AutoIncrement == true) {
379 long inc = Convert.ToInt64(v);
380 col.UpdateAutoIncrementValue (inc);
383 col.DataHasBeenSet = true;
388 /// Gets or sets the custom error description for a row.
390 public string RowError {
391 get { return rowError; }
392 set { rowError = value; }
396 /// Gets the current state of the row in regards to its relationship to the
397 /// DataRowCollection.
399 public DataRowState RowState {
400 get { return rowState; }
403 //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
404 //to a Datatable so I added this method. Delete if there is a better way.
405 internal void AttachRow() {
408 rowState = DataRowState.Added;
411 //FIXME?: Couldn't find a way to set the RowState when removing the DataRow
412 //from a Datatable so I added this method. Delete if there is a better way.
413 internal void DetachRow() {
415 _hasParentCollection = false;
416 rowState = DataRowState.Detached;
420 /// Gets the DataTable for which this row has a schema.
422 public DataTable Table {
423 get { return _table; }
427 /// Gets and sets index of row. This is used from
430 internal int XmlRowID {
431 get { return xmlRowID; }
432 set { xmlRowID = value; }
440 /// Commits all the changes made to this row since the last time AcceptChanges was
443 public void AcceptChanges ()
445 EndEdit(); // in case it hasn't been called
447 case DataRowState.Added:
448 case DataRowState.Modified:
449 rowState = DataRowState.Unchanged;
451 case DataRowState.Deleted:
452 _table.Rows.RemoveInternal (this);
455 case DataRowState.Detached:
456 throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
458 // Accept from detached
459 if (original == null)
460 original = new object[_table.Columns.Count];
461 Array.Copy (current, original, _table.Columns.Count);
465 /// Begins an edit operation on a DataRow object.
468 public void BeginEdit ()
470 if (rowState == DataRowState.Deleted)
471 throw new DeletedRowInaccessibleException ();
472 if (!HasVersion (DataRowVersion.Proposed)) {
473 proposed = new object[_table.Columns.Count];
474 Array.Copy (current, proposed, current.Length);
476 //TODO: Suspend validation
481 /// Cancels the current edit on the row.
484 public void CancelEdit ()
488 if (HasVersion (DataRowVersion.Proposed)) {
490 if (rowState == DataRowState.Modified)
491 rowState = DataRowState.Unchanged;
496 /// Clears the errors for the row, including the RowError and errors set with
499 public void ClearErrors ()
501 rowError = String.Empty;
502 columnErrors = new String[_table.Columns.Count];
506 /// Deletes the DataRow.
509 public void Delete ()
511 _table.DeletingDataRow(this, DataRowAction.Delete);
513 case DataRowState.Added:
514 Table.Rows.RemoveInternal (this);
515 // if row was in Added state we move it to Detached.
518 case DataRowState.Deleted:
521 // check what to do with child rows
522 CheckChildRows(DataRowAction.Delete);
523 rowState = DataRowState.Deleted;
526 _table.DeletedDataRow(this, DataRowAction.Delete);
529 // check the child rows of this row before deleting the row.
530 private void CheckChildRows(DataRowAction action)
533 // in this method we find the row that this row is in a reltion with them.
534 // in shortly we find all child rows of this row.
535 // then we function according to the DeleteRule of the foriegnkey.
538 // 1. find if this row is attached to dataset.
539 // 2. find if EnforceConstraints is true.
540 // 3. find if there are any constraint on the table that the row is in.
541 if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)
543 foreach (DataTable table in _table.DataSet.Tables)
545 // loop on all constraints of the table.
546 ConstraintCollection constraintsCollection = table.Constraints;
547 for (int i = 0; i < constraintsCollection.Count; i++)
549 ForeignKeyConstraint fk = null;
550 if (constraintsCollection[i] is ForeignKeyConstraint)
552 fk = (ForeignKeyConstraint)constraintsCollection[i];
553 if (fk.RelatedTable == _table)
555 //we create a dummy relation because we do not want to duplicate code of GetChild().
556 // we use the dummy relation to find child rows.
557 DataRelation rel = new DataRelation("dummy", fk.RelatedColumns, fk.Columns, false);
559 if (action == DataRowAction.Delete)
560 rule = fk.DeleteRule;
562 rule = fk.UpdateRule;
563 CheckChildRows(rel, action, rule);
571 private void CheckChildRows(DataRelation rel, DataRowAction action, Rule rule)
573 DataRow[] childRows = GetChildRows(rel);
576 case Rule.Cascade: // delete or change all relted rows.
577 if (childRows != null)
579 for (int j = 0; j < childRows.Length; j++)
581 // if action is delete we delete all child rows
582 if (action == DataRowAction.Delete)
584 if (childRows[j].RowState != DataRowState.Deleted)
585 childRows[j].Delete();
587 // if action is change we change the values in the child row
588 else if (action == DataRowAction.Change)
590 // change only the values in the key columns
591 // set the childcolumn value to the new parent row value
592 for (int k = 0; k < rel.ChildColumns.Length; k++)
593 childRows[j][rel.ChildColumns[k]] = this[rel.ParentColumns[k], DataRowVersion.Proposed];
598 case Rule.None: // throw an exception if there are any child rows.
599 if (childRows != null)
601 for (int j = 0; j < childRows.Length; j++)
603 if (childRows[j].RowState != DataRowState.Deleted)
605 string changeStr = "Cannot change this row because constraints are enforced on relation " + rel.RelationName +", and changing this row will strand child rows.";
606 string delStr = "Cannot delete this row because constraints are enforced on relation " + rel.RelationName +", and deleting this row will strand child rows.";
607 string message = action == DataRowAction.Delete ? delStr : changeStr;
608 throw new InvalidConstraintException(message);
613 case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.
614 if (childRows != null)
616 for (int j = 0; j < childRows.Length; j++)
618 DataRow child = childRows[j];
619 if (childRows[j].RowState != DataRowState.Deleted)
621 //set only the key columns to default
622 for (int k = 0; k < rel.ChildColumns.Length; k++)
623 child[rel.ChildColumns[k]] = rel.ChildColumns[k].DefaultValue;
628 case Rule.SetNull: // set the values in the child row to null.
629 if (childRows != null)
631 for (int j = 0; j < childRows.Length; j++)
633 DataRow child = childRows[j];
634 if (childRows[j].RowState != DataRowState.Deleted)
636 // set only the key columns to DBNull
637 for (int k = 0; k < rel.ChildColumns.Length; k++)
638 child.SetNull(rel.ChildColumns[k]);
648 /// Ends the edit occurring on the row.
651 public void EndEdit ()
653 if (_inChangingEvent)
654 throw new InRowChangingEventException("Cannot call EndEdit inside an OnRowChanging event.");
655 if (rowState == DataRowState.Detached)
661 if (HasVersion (DataRowVersion.Proposed))
663 _inChangingEvent = true;
666 _table.ChangingDataRow(this, DataRowAction.Change);
670 _inChangingEvent = false;
672 if (rowState == DataRowState.Unchanged)
673 rowState = DataRowState.Modified;
675 //Calling next method validates UniqueConstraints
679 if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
680 _table.Rows.ValidateDataRowInternal(this);
688 // check all child rows.
689 CheckChildRows(DataRowAction.Change);
693 _table.ChangedDataRow(this, DataRowAction.Change);
698 /// Gets the child rows of this DataRow using the specified DataRelation.
700 public DataRow[] GetChildRows (DataRelation relation)
702 return GetChildRows (relation, DataRowVersion.Current);
706 /// Gets the child rows of a DataRow using the specified RelationName of a
709 public DataRow[] GetChildRows (string relationName)
711 return GetChildRows (Table.DataSet.Relations[relationName]);
715 /// Gets the child rows of a DataRow using the specified DataRelation, and
718 public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version)
720 if (relation == null)
721 return new DataRow[0];
723 if (this.Table == null || RowState == DataRowState.Detached)
724 throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
726 if (relation.DataSet != this.Table.DataSet)
727 throw new ArgumentException();
729 // TODO: Caching for better preformance
730 ArrayList rows = new ArrayList();
731 DataColumn[] parentColumns = relation.ParentColumns;
732 DataColumn[] childColumns = relation.ChildColumns;
733 int numColumn = parentColumns.Length;
734 if (HasVersion(version))
736 foreach (DataRow row in relation.ChildTable.Rows)
738 bool allColumnsMatch = false;
739 if (row.HasVersion(DataRowVersion.Default))
741 allColumnsMatch = true;
742 for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt)
744 if (!this[parentColumns[columnCnt], version].Equals(
745 row[childColumns[columnCnt], DataRowVersion.Default]))
747 allColumnsMatch = false;
752 if (allColumnsMatch) rows.Add(row);
755 DataRow[] result = relation.ChildTable.NewRowArray(rows.Count);
756 rows.CopyTo(result, 0);
761 /// Gets the child rows of a DataRow using the specified RelationName of a
762 /// DataRelation, and DataRowVersion.
764 public DataRow[] GetChildRows (string relationName, DataRowVersion version)
766 return GetChildRows (Table.DataSet.Relations[relationName], version);
770 /// Gets the error description of the specified DataColumn.
772 public string GetColumnError (DataColumn column)
774 return GetColumnError (_table.Columns.IndexOf(column));
778 /// Gets the error description for the column specified by index.
780 public string GetColumnError (int columnIndex)
782 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
783 throw new IndexOutOfRangeException ();
785 string retVal = columnErrors[columnIndex];
787 retVal = string.Empty;
792 /// Gets the error description for the column, specified by name.
794 public string GetColumnError (string columnName)
796 return GetColumnError (_table.Columns.IndexOf(columnName));
800 /// Gets an array of columns that have errors.
802 public DataColumn[] GetColumnsInError ()
804 ArrayList dataColumns = new ArrayList ();
806 for (int i = 0; i < columnErrors.Length; i += 1)
808 if (columnErrors[i] != null && columnErrors[i] != String.Empty)
809 dataColumns.Add (_table.Columns[i]);
812 return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));
816 /// Gets the parent row of a DataRow using the specified DataRelation.
818 public DataRow GetParentRow (DataRelation relation)
820 return GetParentRow (relation, DataRowVersion.Current);
824 /// Gets the parent row of a DataRow using the specified RelationName of a
827 public DataRow GetParentRow (string relationName)
829 return GetParentRow (relationName, DataRowVersion.Current);
833 /// Gets the parent row of a DataRow using the specified DataRelation, and
836 public DataRow GetParentRow (DataRelation relation, DataRowVersion version)
838 DataRow[] rows = GetParentRows(relation, version);
839 if (rows.Length == 0) return null;
844 /// Gets the parent row of a DataRow using the specified RelationName of a
845 /// DataRelation, and DataRowVersion.
847 public DataRow GetParentRow (string relationName, DataRowVersion version)
849 return GetParentRow (Table.DataSet.Relations[relationName], version);
853 /// Gets the parent rows of a DataRow using the specified DataRelation.
855 public DataRow[] GetParentRows (DataRelation relation)
857 return GetParentRows (relation, DataRowVersion.Current);
861 /// Gets the parent rows of a DataRow using the specified RelationName of a
864 public DataRow[] GetParentRows (string relationName)
866 return GetParentRows (relationName, DataRowVersion.Current);
870 /// Gets the parent rows of a DataRow using the specified DataRelation, and
873 public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version)
875 // TODO: Caching for better preformance
876 if (relation == null)
877 return new DataRow[0];
879 if (this.Table == null || RowState == DataRowState.Detached)
880 throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
882 if (relation.DataSet != this.Table.DataSet)
883 throw new ArgumentException();
885 ArrayList rows = new ArrayList();
886 DataColumn[] parentColumns = relation.ParentColumns;
887 DataColumn[] childColumns = relation.ChildColumns;
888 int numColumn = parentColumns.Length;
889 if (HasVersion(version))
891 foreach (DataRow row in relation.ParentTable.Rows)
893 bool allColumnsMatch = false;
894 if (row.HasVersion(DataRowVersion.Default))
896 allColumnsMatch = true;
897 for (int columnCnt = 0; columnCnt < numColumn; columnCnt++)
899 if (!this[childColumns[columnCnt], version].Equals(
900 row[parentColumns[columnCnt], DataRowVersion.Default]))
902 allColumnsMatch = false;
907 if (allColumnsMatch) rows.Add(row);
911 DataRow[] result = relation.ParentTable.NewRowArray(rows.Count);
912 rows.CopyTo(result, 0);
917 /// Gets the parent rows of a DataRow using the specified RelationName of a
918 /// DataRelation, and DataRowVersion.
920 public DataRow[] GetParentRows (string relationName, DataRowVersion version)
922 return GetParentRows (Table.DataSet.Relations[relationName], version);
926 /// Gets a value indicating whether a specified version exists.
928 public bool HasVersion (DataRowVersion version)
932 case DataRowVersion.Default:
933 if (rowState == DataRowState.Deleted)
935 if (rowState == DataRowState.Detached)
936 return proposed != null;
938 case DataRowVersion.Proposed:
939 if (rowState == DataRowState.Deleted)
941 return (proposed != null);
942 case DataRowVersion.Current:
943 if (rowState == DataRowState.Deleted || rowState == DataRowState.Detached)
945 return (current != null);
946 case DataRowVersion.Original:
947 if (rowState == DataRowState.Detached)
949 return (original != null);
955 /// Gets a value indicating whether the specified DataColumn contains a null value.
957 public bool IsNull (DataColumn column)
959 object o = this[column];
960 return (o == null || o == DBNull.Value);
964 /// Gets a value indicating whether the column at the specified index contains a null
967 public bool IsNull (int columnIndex)
969 object o = this[columnIndex];
970 return (o == null || o == DBNull.Value);
974 /// Gets a value indicating whether the named column contains a null value.
976 public bool IsNull (string columnName)
978 object o = this[columnName];
979 return (o == null || o == DBNull.Value);
983 /// Gets a value indicating whether the specified DataColumn and DataRowVersion
984 /// contains a null value.
986 public bool IsNull (DataColumn column, DataRowVersion version)
988 object o = this[column, version];
989 return (o == null || o == DBNull.Value);
993 /// Rejects all changes made to the row since AcceptChanges was last called.
995 public void RejectChanges ()
997 if (RowState == DataRowState.Detached)
998 throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
999 // If original is null, then nothing has happened since AcceptChanges
1000 // was last called. We have no "original" to go back to.
1001 if (original != null)
1003 Array.Copy (original, current, _table.Columns.Count);
1005 _table.ChangedDataRow (this, DataRowAction.Rollback);
1009 case DataRowState.Added:
1010 _table.Rows.RemoveInternal (this);
1012 case DataRowState.Modified:
1013 rowState = DataRowState.Unchanged;
1015 case DataRowState.Deleted:
1016 rowState = DataRowState.Unchanged;
1022 // If rows are just loaded via Xml the original values are null.
1023 // So in this case we have to remove all columns.
1024 // FIXME: I'm not realy sure, does this break something else, but
1027 if ((rowState & DataRowState.Added) > 0)
1029 _table.Rows.RemoveInternal (this);
1030 // if row was in Added state we move it to Detached.
1037 /// Sets the error description for a column specified as a DataColumn.
1039 public void SetColumnError (DataColumn column, string error)
1041 SetColumnError (_table.Columns.IndexOf (column), error);
1045 /// Sets the error description for a column specified by index.
1047 public void SetColumnError (int columnIndex, string error)
1049 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
1050 throw new IndexOutOfRangeException ();
1051 columnErrors[columnIndex] = error;
1055 /// Sets the error description for a column specified by name.
1057 public void SetColumnError (string columnName, string error)
1059 SetColumnError (_table.Columns.IndexOf (columnName), error);
1063 /// Sets the value of the specified DataColumn to a null value.
1065 protected void SetNull (DataColumn column)
1067 this[column] = DBNull.Value;
1071 /// Sets the parent row of a DataRow with specified new parent DataRow.
1074 public void SetParentRow (DataRow parentRow)
1076 SetParentRow(parentRow, null);
1080 /// Sets the parent row of a DataRow with specified new parent DataRow and
1084 public void SetParentRow (DataRow parentRow, DataRelation relation)
1086 if (_table == null || parentRow.Table == null || RowState == DataRowState.Detached)
1087 throw new RowNotInTableException("This row has been removed from a table and does not have any data. BeginEdit() will allow creation of new data in this row.");
1089 if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
1090 throw new ArgumentException();
1093 if (relation == null)
1095 foreach (DataRelation parentRel in _table.ParentRelations)
1097 DataColumn[] childCols = parentRel.ChildKeyConstraint.Columns;
1098 DataColumn[] parentCols = parentRel.ChildKeyConstraint.RelatedColumns;
1100 for (int i = 0; i < parentCols.Length; i++)
1102 if (parentRow == null)
1103 this[childCols[i].Ordinal] = DBNull.Value;
1105 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1112 DataColumn[] childCols = relation.ChildKeyConstraint.Columns;
1113 DataColumn[] parentCols = relation.ChildKeyConstraint.RelatedColumns;
1115 for (int i = 0; i < parentCols.Length; i++)
1117 if (parentRow == null)
1118 this[childCols[i].Ordinal] = DBNull.Value;
1120 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1126 //Copy all values of this DataaRow to the row parameter.
1127 internal void CopyValuesToRow(DataRow row)
1131 throw new ArgumentNullException("row");
1133 throw new ArgumentException("'row' is the same as this object");
1135 DataColumnCollection columns = Table.Columns;
1137 for(int i = 0; i < columns.Count; i++){
1139 string columnName = columns[i].ColumnName;
1140 int index = row.Table.Columns.IndexOf(columnName);
1141 //if a column with the same name exists in both rows copy the values
1143 if (HasVersion(DataRowVersion.Original))
1145 if (row.original == null)
1146 row.original = new object[row.Table.Columns.Count];
1147 row.original[index] = row.SetColumnValue(original[i], index);
1149 if (HasVersion(DataRowVersion.Current))
1151 if (row.current == null)
1152 row.current = new object[row.Table.Columns.Count];
1153 row.current[index] = row.SetColumnValue(current[i], index);
1155 if (HasVersion(DataRowVersion.Proposed))
1157 if (row.proposed == null)
1158 row.proposed = new object[row.Table.Columns.Count];
1159 row.proposed[index] = row.SetColumnValue(proposed[i], index);
1162 //Saving the current value as the column value
1163 row[index] = row.current[index];
1168 row.rowState = RowState;
1169 row.RowError = RowError;
1170 row.columnErrors = columnErrors;
1174 public void CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs args)
1176 // if a column is added we hava to add an additional value the
1177 // the priginal, current and propoed arrays.
1178 // this scenario can happened in merge operation.
1180 if (args.Action == System.ComponentModel.CollectionChangeAction.Add)
1183 if (current != null)
1185 tmp = new object[current.Length + 1];
1186 Array.Copy (current, tmp, current.Length);
1187 tmp[tmp.Length - 1] = SetColumnValue(null, tmp.Length - 1);
1190 if (proposed != null)
1192 tmp = new object[proposed.Length + 1];
1193 Array.Copy (proposed, tmp, proposed.Length);
1194 tmp[tmp.Length - 1] = SetColumnValue(null, tmp.Length - 1);
1197 if(original != null)
1199 tmp = new object[original.Length + 1];
1200 Array.Copy (original, tmp, original.Length);
1201 tmp[tmp.Length - 1] = SetColumnValue(null, tmp.Length - 1);
1208 internal bool IsRowChanged(DataRowState rowState) {
1209 if((RowState & rowState) != 0)
1212 //we need to find if child rows of this row changed.
1213 //if yes - we should return true
1215 // if the rowState is deleted we should get the original version of the row
1216 // else - we should get the current version of the row.
1217 DataRowVersion version = (rowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current;
1218 int count = Table.ChildRelations.Count;
1219 for (int i = 0; i < count; i++){
1220 DataRelation rel = Table.ChildRelations[i];
1221 DataRow[] childRows = GetChildRows(rel, version);
1222 for (int j = 0; j < childRows.Length; j++){
1223 if (childRows[j].IsRowChanged(rowState))
1231 internal bool HasParentCollection
1235 return _hasParentCollection;
1239 _hasParentCollection = value;
1243 internal void CheckNullConstraints()
1245 if (_nullConstraintViolation)
1247 for (int i = 0; i < proposed.Length; i++)
1249 if (this[i] == DBNull.Value && !_table.Columns[i].AllowDBNull)
1250 throw new NoNullAllowedException(_nullConstraintMessage);
1252 _nullConstraintViolation = false;
1256 #endregion // Methods