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;
49 /// This member supports the .NET Framework infrastructure and is not intended to be
50 /// used directly from your code.
52 protected internal DataRow (DataRowBuilder builder)
54 _table = builder.Table;
58 proposed = new object[_table.Columns.Count];
59 for (int c = 0; c < _table.Columns.Count; c++)
61 proposed[c] = DBNull.Value;
64 columnErrors = new string[_table.Columns.Count];
65 rowError = String.Empty;
67 //on first creating a DataRow it is always detached.
68 rowState = DataRowState.Detached;
70 foreach (DataColumn Col in _table.Columns) {
72 if (Col.AutoIncrement) {
73 this [Col] = Col.AutoIncrementValue();
76 _table.Columns.CollectionChanged += new System.ComponentModel.CollectionChangeEventHandler(CollectionChanged);
85 /// Gets a value indicating whether there are errors in a row.
87 public bool HasErrors {
90 if (RowError != string.Empty)
93 for (int i= 0; i < columnErrors.Length; i++){
94 if (columnErrors[i] != null && columnErrors[i] != string.Empty)
103 /// Gets or sets the data stored in the column specified by name.
105 public object this[string columnName] {
106 get { return this[columnName, DataRowVersion.Default]; }
108 int columnIndex = _table.Columns.IndexOf (columnName);
109 if (columnIndex == -1)
110 throw new IndexOutOfRangeException ();
111 this[columnIndex] = value;
116 /// Gets or sets the data stored in specified DataColumn
118 public object this[DataColumn column] {
121 return this[column, DataRowVersion.Default];}
123 int columnIndex = _table.Columns.IndexOf (column);
124 if (columnIndex == -1)
125 throw new ArgumentException ("The column does not belong to this table.");
126 this[columnIndex] = value;
131 /// Gets or sets the data stored in column specified by index.
133 public object this[int columnIndex] {
134 get { return this[columnIndex, DataRowVersion.Default]; }
136 if (columnIndex < 0 || columnIndex > _table.Columns.Count)
137 throw new IndexOutOfRangeException ();
138 if (rowState == DataRowState.Deleted)
139 throw new DeletedRowInaccessibleException ();
140 DataColumn column = _table.Columns[columnIndex];
141 _table.ChangingDataColumn (this, column, value);
144 bool orginalEditing = editing;
145 if (!orginalEditing) BeginEdit ();
146 object v = SetColumnValue (value, columnIndex);
147 proposed[columnIndex] = v;
148 _table.ChangedDataColumn (this, column, v);
149 if (!orginalEditing) EndEdit ();
154 /// Gets the specified version of data stored in the named column.
156 public object this[string columnName, DataRowVersion version] {
158 int columnIndex = _table.Columns.IndexOf (columnName);
159 if (columnIndex == -1)
160 throw new IndexOutOfRangeException ();
161 return this[columnIndex, version];
166 /// Gets the specified version of data stored in the specified DataColumn.
168 public object this[DataColumn column, DataRowVersion version] {
170 int columnIndex = _table.Columns.IndexOf (column);
171 if (columnIndex == -1)
172 throw new ArgumentException ("The column does not belong to this table.");
173 return this[columnIndex, version];
178 /// Gets the data stored in the column, specified by index and version of the data to
181 public object this[int columnIndex, DataRowVersion version] {
183 if (columnIndex < 0 || columnIndex > _table.Columns.Count)
184 throw new IndexOutOfRangeException ();
185 // Accessing deleted rows
186 if (rowState == DataRowState.Deleted && version != DataRowVersion.Original)
187 throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
188 // Non-existent version
189 if (rowState == DataRowState.Detached && version == DataRowVersion.Current || !HasVersion (version))
190 throw new VersionNotFoundException (Locale.GetText ("There is no " + version.ToString () + " data to access."));
192 case DataRowVersion.Default:
193 if (editing || rowState == DataRowState.Detached)
194 return proposed[columnIndex];
195 return current[columnIndex];
196 case DataRowVersion.Proposed:
197 return proposed[columnIndex];
198 case DataRowVersion.Current:
199 return current[columnIndex];
200 case DataRowVersion.Original:
201 return original[columnIndex];
203 throw new ArgumentException ();
209 /// Gets or sets all of the values for this row through an array.
212 public object[] ItemArray {
214 // Accessing deleted rows
\r
215 if (rowState == DataRowState.Deleted)
\r
216 throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
\r
221 if (value.Length > _table.Columns.Count)
222 throw new ArgumentException ();
224 if (rowState == DataRowState.Deleted)
225 throw new DeletedRowInaccessibleException ();
227 object[] newItems = new object[_table.Columns.Count];
229 for (int i = 0; i < _table.Columns.Count; i++) {
231 if (i < value.Length)
236 newItems[i] = SetColumnValue (v, i);
239 bool orginalEditing = editing;
240 if (!orginalEditing) BeginEdit ();
242 if (!orginalEditing) EndEdit ();
246 private object SetColumnValue (object v, int index)
\r
248 object newval = null;
\r
249 DataColumn col = _table.Columns[index];
\r
251 if (_hasParentCollection && col.ReadOnly && v != this[index])
\r
252 throw new ReadOnlyException ();
\r
256 if(col.DefaultValue != DBNull.Value)
\r
258 newval = col.DefaultValue;
\r
260 else if(col.AutoIncrement == true)
\r
262 newval = this [index];
\r
266 if (!col.AllowDBNull)
\r
268 //Constraint violations during data load is raise in DataTable EndLoad
\r
269 this._nullConstraintViolation = true;
\r
270 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
\r
273 newval = DBNull.Value;
\r
276 else if (v == DBNull.Value)
\r
279 if (!col.AllowDBNull)
\r
281 //Constraint violations during data load is raise in DataTable EndLoad
\r
282 this._nullConstraintViolation = true;
\r
283 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
\r
286 newval = DBNull.Value;
\r
290 Type vType = v.GetType(); // data type of value
\r
291 Type cType = col.DataType; // column data type
\r
292 if (cType != vType)
\r
294 TypeCode typeCode = Type.GetTypeCode(cType);
\r
296 case TypeCode.Boolean :
\r
297 v = Convert.ToBoolean (v);
\r
299 case TypeCode.Byte :
\r
300 v = Convert.ToByte (v);
\r
302 case TypeCode.Char :
\r
303 v = Convert.ToChar (v);
\r
305 case TypeCode.DateTime :
\r
306 v = Convert.ToDateTime (v);
\r
308 case TypeCode.Decimal :
\r
309 v = Convert.ToDecimal (v);
\r
311 case TypeCode.Double :
\r
312 v = Convert.ToDouble (v);
\r
314 case TypeCode.Int16 :
\r
315 v = Convert.ToInt16 (v);
\r
317 case TypeCode.Int32 :
\r
318 v = Convert.ToInt32 (v);
\r
320 case TypeCode.Int64 :
\r
321 v = Convert.ToInt64 (v);
\r
323 case TypeCode.SByte :
\r
324 v = Convert.ToSByte (v);
\r
326 case TypeCode.Single :
\r
327 v = Convert.ToSingle (v);
\r
329 case TypeCode.String :
\r
330 v = Convert.ToString (v);
\r
332 case TypeCode.UInt16 :
\r
333 v = Convert.ToUInt16 (v);
\r
335 case TypeCode.UInt32 :
\r
336 v = Convert.ToUInt32 (v);
\r
338 case TypeCode.UInt64 :
\r
339 v = Convert.ToUInt64 (v);
\r
343 switch(cType.ToString()) {
\r
344 case "System.TimeSpan" :
\r
345 v = (System.TimeSpan) v;
\r
347 case "System.Type" :
\r
348 v = (System.Type) v;
\r
350 case "System.Object" :
\r
351 //v = (System.Object) v;
\r
354 if (!cType.IsArray)
\r
355 throw new InvalidCastException("Type not supported.");
\r
360 vType = v.GetType();
\r
363 if(col.AutoIncrement == true) {
\r
364 long inc = Convert.ToInt64(v);
\r
365 col.UpdateAutoIncrementValue (inc);
\r
368 col.DataHasBeenSet = true;
\r
374 /// Gets or sets the custom error description for a row.
376 public string RowError {
377 get { return rowError; }
378 set { rowError = value; }
382 /// Gets the current state of the row in regards to its relationship to the
383 /// DataRowCollection.
385 public DataRowState RowState {
386 get { return rowState; }
389 //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
390 //to a Datatable so I added this method. Delete if there is a better way.
391 internal void AttachRow() {
394 rowState = DataRowState.Added;
397 //FIXME?: Couldn't find a way to set the RowState when removing the DataRow
398 //from a Datatable so I added this method. Delete if there is a better way.
399 internal void DetachRow() {
401 _hasParentCollection = false;
402 rowState = DataRowState.Detached;
406 /// Gets the DataTable for which this row has a schema.
408 public DataTable Table {
409 get { return _table; }
413 /// Gets and sets index of row. This is used from
416 internal int XmlRowID {
417 get { return xmlRowID; }
418 set { xmlRowID = value; }
426 /// Commits all the changes made to this row since the last time AcceptChanges was
429 public void AcceptChanges ()
431 EndEdit(); // in case it hasn't been called
433 case DataRowState.Added:
434 case DataRowState.Modified:
435 rowState = DataRowState.Unchanged;
437 case DataRowState.Deleted:
438 _table.Rows.RemoveInternal (this);
440 case DataRowState.Detached:
441 throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
443 // Accept from detached
444 if (original == null)
445 original = new object[_table.Columns.Count];
446 Array.Copy (current, original, _table.Columns.Count);
450 /// Begins an edit operation on a DataRow object.
453 public void BeginEdit ()
455 if (rowState == DataRowState.Deleted)
456 throw new DeletedRowInaccessibleException ();
457 if (!HasVersion (DataRowVersion.Proposed)) {
458 proposed = new object[_table.Columns.Count];
459 Array.Copy (current, proposed, current.Length);
461 //TODO: Suspend validation
466 /// Cancels the current edit on the row.
469 public void CancelEdit ()
473 if (HasVersion (DataRowVersion.Proposed)) {
475 if (rowState == DataRowState.Modified)
476 rowState = DataRowState.Unchanged;
481 /// Clears the errors for the row, including the RowError and errors set with
484 public void ClearErrors ()
486 rowError = String.Empty;
487 columnErrors = new String[_table.Columns.Count];
491 /// Deletes the DataRow.
494 public void Delete ()
496 _table.DeletingDataRow(this, DataRowAction.Delete);
498 case DataRowState.Added:
499 Table.Rows.RemoveInternal (this);
501 case DataRowState.Deleted:
502 throw new DeletedRowInaccessibleException ();
504 // check what to do with child rows
505 CheckChildRows(DataRowAction.Delete);
506 rowState = DataRowState.Deleted;
509 _table.DeletedDataRow(this, DataRowAction.Delete);
512 // check the child rows of this row before deleting the row.
513 private void CheckChildRows(DataRowAction action)
516 // in this method we find the row that this row is in a reltion with them.
517 // in shortly we find all child rows of this row.
518 // then we function according to the DeleteRule of the foriegnkey.
521 // 1. find if this row is attached to dataset.
522 // 2. find if EnforceConstraints is true.
523 // 3. find if there are any constraint on the table that the row is in.
524 if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)
526 foreach (DataTable table in _table.DataSet.Tables)
528 // loop on all constraints of the table.
529 ConstraintCollection constraintsCollection = table.Constraints;
530 for (int i = 0; i < constraintsCollection.Count; i++)
532 ForeignKeyConstraint fk = null;
533 if (constraintsCollection[i] is ForeignKeyConstraint)
535 fk = (ForeignKeyConstraint)constraintsCollection[i];
536 if (fk.RelatedTable == _table)
538 //we create a dummy relation because we do not want to duplicate code of GetChild().
539 // we use the dummy relation to find child rows.
540 DataRelation rel = new DataRelation("dummy", fk.RelatedColumns, fk.Columns, false);
542 if (action == DataRowAction.Delete)
543 rule = fk.DeleteRule;
545 rule = fk.UpdateRule;
546 CheckChildRows(rel, action, rule);
554 private void CheckChildRows(DataRelation rel, DataRowAction action, Rule rule)
556 DataRow[] childRows = GetChildRows(rel);
559 case Rule.Cascade: // delete or change all relted rows.
560 if (childRows != null)
562 for (int j = 0; j < childRows.Length; j++)
564 // if action is delete we delete all child rows
565 if (action == DataRowAction.Delete)
567 if (childRows[j].RowState != DataRowState.Deleted)
568 childRows[j].Delete();
570 // if action is change we change the values in the child row
571 else if (action == DataRowAction.Change)
573 // change only the values in the key columns
574 // set the childcolumn value to the new parent row value
575 for (int k = 0; k < rel.ChildColumns.Length; k++)
576 childRows[j][rel.ChildColumns[k]] = this[rel.ParentColumns[k], DataRowVersion.Proposed];
581 case Rule.None: // throw an exception if there are any child rows.
582 if (childRows != null)
584 for (int j = 0; j < childRows.Length; j++)
586 if (childRows[j].RowState != DataRowState.Deleted)
588 string changeStr = "Cannot change this row because constraints are enforced on relation " + rel.RelationName +", and changing this row will strand child rows.";
589 string delStr = "Cannot delete this row because constraints are enforced on relation " + rel.RelationName +", and deleting this row will strand child rows.";
590 string message = action == DataRowAction.Delete ? delStr : changeStr;
591 throw new InvalidConstraintException(message);
596 case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.
597 if (childRows != null)
599 for (int j = 0; j < childRows.Length; j++)
601 DataRow child = childRows[j];
602 if (childRows[j].RowState != DataRowState.Deleted)
604 //set only the key columns to default
605 for (int k = 0; k < rel.ChildColumns.Length; k++)
606 child[rel.ChildColumns[k]] = rel.ChildColumns[k].DefaultValue;
611 case Rule.SetNull: // set the values in the child row to null.
612 if (childRows != null)
614 for (int j = 0; j < childRows.Length; j++)
616 DataRow child = childRows[j];
617 if (childRows[j].RowState != DataRowState.Deleted)
619 // set only the key columns to DBNull
620 for (int k = 0; k < rel.ChildColumns.Length; k++)
621 child.SetNull(rel.ChildColumns[k]);
631 /// Ends the edit occurring on the row.
634 public void EndEdit ()
636 if (rowState == DataRowState.Detached)
\r
642 if (HasVersion (DataRowVersion.Proposed))
\r
644 _table.ChangingDataRow(this, DataRowAction.Change);
\r
645 if (rowState == DataRowState.Unchanged)
\r
646 rowState = DataRowState.Modified;
\r
648 //Calling next method validates UniqueConstraints
\r
652 if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
\r
653 _table.Rows.ValidateDataRowInternal(this);
\r
655 catch (Exception e)
\r
661 // check all child rows.
\r
662 CheckChildRows(DataRowAction.Change);
\r
663 current = proposed;
\r
666 _table.ChangedDataRow(this, DataRowAction.Change);
\r
671 /// Gets the child rows of this DataRow using the specified DataRelation.
673 public DataRow[] GetChildRows (DataRelation relation)
675 return GetChildRows (relation, DataRowVersion.Current);
679 /// Gets the child rows of a DataRow using the specified RelationName of a
682 public DataRow[] GetChildRows (string relationName)
684 return GetChildRows (Table.DataSet.Relations[relationName]);
688 /// Gets the child rows of a DataRow using the specified DataRelation, and
691 public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version)
693 if (relation == null)
694 return new DataRow[0];
696 if (this.Table == null)
697 throw new RowNotInTableException();
699 if (relation.DataSet != this.Table.DataSet)
700 throw new ArgumentException();
702 // TODO: Caching for better preformance
703 ArrayList rows = new ArrayList();
704 DataColumn[] parentColumns = relation.ParentColumns;
705 DataColumn[] childColumns = relation.ChildColumns;
706 int numColumn = parentColumns.Length;
707 if (HasVersion(version))
709 foreach (DataRow row in relation.ChildTable.Rows)
711 bool allColumnsMatch = false;
712 if (row.HasVersion(DataRowVersion.Default))
714 allColumnsMatch = true;
715 for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt)
717 if (!this[parentColumns[columnCnt], version].Equals(
718 row[childColumns[columnCnt], DataRowVersion.Default]))
720 allColumnsMatch = false;
725 if (allColumnsMatch) rows.Add(row);
728 return rows.ToArray(typeof(DataRow)) as DataRow[];
732 /// Gets the child rows of a DataRow using the specified RelationName of a
733 /// DataRelation, and DataRowVersion.
735 public DataRow[] GetChildRows (string relationName, DataRowVersion version)
737 return GetChildRows (Table.DataSet.Relations[relationName], version);
741 /// Gets the error description of the specified DataColumn.
743 public string GetColumnError (DataColumn column)
745 return GetColumnError (_table.Columns.IndexOf(column));
749 /// Gets the error description for the column specified by index.
751 public string GetColumnError (int columnIndex)
753 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
754 throw new IndexOutOfRangeException ();
756 string retVal = columnErrors[columnIndex];
758 retVal = string.Empty;
763 /// Gets the error description for the column, specified by name.
765 public string GetColumnError (string columnName)
767 return GetColumnError (_table.Columns.IndexOf(columnName));
771 /// Gets an array of columns that have errors.
773 public DataColumn[] GetColumnsInError ()
775 ArrayList dataColumns = new ArrayList ();
777 for (int i = 0; i < columnErrors.Length; i += 1)
779 if (columnErrors[i] != null && columnErrors[i] != String.Empty)
780 dataColumns.Add (_table.Columns[i]);
783 return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));
787 /// Gets the parent row of a DataRow using the specified DataRelation.
789 public DataRow GetParentRow (DataRelation relation)
791 return GetParentRow (relation, DataRowVersion.Current);
795 /// Gets the parent row of a DataRow using the specified RelationName of a
798 public DataRow GetParentRow (string relationName)
800 return GetParentRow (relationName, DataRowVersion.Current);
804 /// Gets the parent row of a DataRow using the specified DataRelation, and
807 public DataRow GetParentRow (DataRelation relation, DataRowVersion version)
809 DataRow[] rows = GetParentRows(relation, version);
810 if (rows.Length == 0) return null;
815 /// Gets the parent row of a DataRow using the specified RelationName of a
816 /// DataRelation, and DataRowVersion.
818 public DataRow GetParentRow (string relationName, DataRowVersion version)
820 return GetParentRow (Table.DataSet.Relations[relationName], version);
824 /// Gets the parent rows of a DataRow using the specified DataRelation.
826 public DataRow[] GetParentRows (DataRelation relation)
828 return GetParentRows (relation, DataRowVersion.Current);
832 /// Gets the parent rows of a DataRow using the specified RelationName of a
835 public DataRow[] GetParentRows (string relationName)
837 return GetParentRows (relationName, DataRowVersion.Current);
841 /// Gets the parent rows of a DataRow using the specified DataRelation, and
844 public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version)
846 // TODO: Caching for better preformance
847 if (relation == null)
848 return new DataRow[0];
850 if (this.Table == null)
851 throw new RowNotInTableException();
853 if (relation.DataSet != this.Table.DataSet)
854 throw new ArgumentException();
856 ArrayList rows = new ArrayList();
857 DataColumn[] parentColumns = relation.ParentColumns;
858 DataColumn[] childColumns = relation.ChildColumns;
859 int numColumn = parentColumns.Length;
860 if (HasVersion(version))
862 foreach (DataRow row in relation.ParentTable.Rows)
864 bool allColumnsMatch = false;
865 if (row.HasVersion(DataRowVersion.Default))
867 allColumnsMatch = true;
868 for (int columnCnt = 0; columnCnt < numColumn; columnCnt++)
870 if (!this[childColumns[columnCnt], version].Equals(
871 row[parentColumns[columnCnt], DataRowVersion.Default]))
873 allColumnsMatch = false;
878 if (allColumnsMatch) rows.Add(row);
881 return rows.ToArray(typeof(DataRow)) as DataRow[];
885 /// Gets the parent rows of a DataRow using the specified RelationName of a
886 /// DataRelation, and DataRowVersion.
888 public DataRow[] GetParentRows (string relationName, DataRowVersion version)
890 return GetParentRows (Table.DataSet.Relations[relationName], version);
894 /// Gets a value indicating whether a specified version exists.
896 public bool HasVersion (DataRowVersion version)
900 case DataRowVersion.Default:
901 if (rowState == DataRowState.Deleted)
903 if (rowState == DataRowState.Detached)
904 return proposed != null;
906 case DataRowVersion.Proposed:
907 if (rowState == DataRowState.Deleted)
909 return (proposed != null);
910 case DataRowVersion.Current:
911 if (rowState == DataRowState.Deleted || rowState == DataRowState.Detached)
913 return (current != null);
914 case DataRowVersion.Original:
915 if (rowState == DataRowState.Detached)
917 return (original != null);
923 /// Gets a value indicating whether the specified DataColumn contains a null value.
925 public bool IsNull (DataColumn column)
927 object o = this[column];
928 return (o == null || o == DBNull.Value);
932 /// Gets a value indicating whether the column at the specified index contains a null
935 public bool IsNull (int columnIndex)
937 object o = this[columnIndex];
938 return (o == null || o == DBNull.Value);
942 /// Gets a value indicating whether the named column contains a null value.
944 public bool IsNull (string columnName)
946 object o = this[columnName];
947 return (o == null || o == DBNull.Value);
951 /// Gets a value indicating whether the specified DataColumn and DataRowVersion
952 /// contains a null value.
954 public bool IsNull (DataColumn column, DataRowVersion version)
956 object o = this[column, version];
957 return (o == null || o == DBNull.Value);
961 /// Rejects all changes made to the row since AcceptChanges was last called.
963 public void RejectChanges ()
965 // If original is null, then nothing has happened since AcceptChanges
966 // was last called. We have no "original" to go back to.
967 if (original != null)
969 Array.Copy (original, current, _table.Columns.Count);
971 _table.ChangedDataRow (this, DataRowAction.Rollback);
975 case DataRowState.Added:
976 _table.Rows.RemoveInternal (this);
978 case DataRowState.Modified:
979 rowState = DataRowState.Unchanged;
981 case DataRowState.Deleted:
982 rowState = DataRowState.Unchanged;
988 // If rows are just loaded via Xml the original values are null.
989 // So in this case we have to remove all columns.
990 // FIXME: I'm not realy sure, does this break something else, but
993 if ((rowState & DataRowState.Added) > 0)
994 _table.Rows.RemoveInternal (this);
999 /// Sets the error description for a column specified as a DataColumn.
1001 public void SetColumnError (DataColumn column, string error)
1003 SetColumnError (_table.Columns.IndexOf (column), error);
1007 /// Sets the error description for a column specified by index.
1009 public void SetColumnError (int columnIndex, string error)
1011 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
1012 throw new IndexOutOfRangeException ();
1013 columnErrors[columnIndex] = error;
1017 /// Sets the error description for a column specified by name.
1019 public void SetColumnError (string columnName, string error)
1021 SetColumnError (_table.Columns.IndexOf (columnName), error);
1025 /// Sets the value of the specified DataColumn to a null value.
1027 protected void SetNull (DataColumn column)
1029 this[column] = DBNull.Value;
1033 /// Sets the parent row of a DataRow with specified new parent DataRow.
1036 public void SetParentRow (DataRow parentRow)
1038 SetParentRow(parentRow, null);
1042 /// Sets the parent row of a DataRow with specified new parent DataRow and
1046 public void SetParentRow (DataRow parentRow, DataRelation relation)
1048 if (_table == null || parentRow.Table == null)
1049 throw new RowNotInTableException();
1051 if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
1052 throw new ArgumentException();
1055 if (relation == null)
1057 foreach (DataRelation parentRel in _table.ParentRelations)
1059 DataColumn[] childCols = parentRel.ChildKeyConstraint.Columns;
1060 DataColumn[] parentCols = parentRel.ChildKeyConstraint.RelatedColumns;
1062 for (int i = 0; i < parentCols.Length; i++)
1064 if (parentRow == null)
1065 this[childCols[i].Ordinal] = DBNull.Value;
1067 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1074 DataColumn[] childCols = relation.ChildKeyConstraint.Columns;
1075 DataColumn[] parentCols = relation.ChildKeyConstraint.RelatedColumns;
1077 for (int i = 0; i < parentCols.Length; i++)
1079 if (parentRow == null)
1080 this[childCols[i].Ordinal] = DBNull.Value;
1082 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1088 //Copy all values of this DataaRow to the row parameter.
1089 internal void CopyValuesToRow(DataRow row)
1093 throw new ArgumentNullException("row");
1095 throw new ArgumentException("'row' is the same as this object");
1097 DataColumnCollection columns = Table.Columns;
1099 for(int i = 0; i < columns.Count; i++){
1101 string columnName = columns[i].ColumnName;
1102 int index = row.Table.Columns.IndexOf(columnName);
1103 //if a column with the same name exists in both rows copy the values
1105 if (HasVersion(DataRowVersion.Original))
1107 if (row.original == null)
1108 row.original = new object[row.Table.Columns.Count];
1109 row.original[index] = row.SetColumnValue(original[i], index);
1111 if (HasVersion(DataRowVersion.Current))
1113 if (row.current == null)
1114 row.current = new object[row.Table.Columns.Count];
1115 row.current[index] = row.SetColumnValue(current[i], index);
1117 if (HasVersion(DataRowVersion.Proposed))
1119 if (row.proposed == null)
1120 row.proposed = new object[row.Table.Columns.Count];
1121 row.proposed[index] = row.SetColumnValue(proposed[i], index);
1124 //Saving the current value as the column value
1125 row[index] = row.current[index];
1130 row.rowState = RowState;
1131 row.RowError = RowError;
1132 row.columnErrors = columnErrors;
1136 public void CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs args)
1138 // if a column is added we hava to add an additional value the
1139 // the priginal, current and propoed arrays.
1140 // this scenario can happened in merge operation.
1142 if (args.Action == System.ComponentModel.CollectionChangeAction.Add)
1145 if (current != null)
1147 tmp = new object[current.Length + 1];
1148 Array.Copy (current, tmp, current.Length);
1149 tmp[tmp.Length - 1] = DBNull.Value;
1152 if (proposed != null)
1154 tmp = new object[proposed.Length + 1];
1155 Array.Copy (proposed, tmp, proposed.Length);
1156 tmp[tmp.Length - 1] = DBNull.Value;
1159 if(original != null)
1161 tmp = new object[original.Length + 1];
1162 Array.Copy (original, tmp, original.Length);
1163 tmp[tmp.Length - 1] = DBNull.Value;
1170 internal bool IsRowChanged(DataRowState rowState) {
1171 if((RowState & rowState) != 0)
1174 //we need to find if child rows of this row changed.
1175 //if yes - we should return true
1177 // if the rowState is deleted we should get the original version of the row
1178 // else - we should get the current version of the row.
1179 DataRowVersion version = (rowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current;
1180 int count = Table.ChildRelations.Count;
1181 for (int i = 0; i < count; i++){
1182 DataRelation rel = Table.ChildRelations[i];
1183 DataRow[] childRows = GetChildRows(rel, version);
1184 for (int j = 0; j < childRows.Length; j++){
1185 if (childRows[j].IsRowChanged(rowState))
1193 internal bool HasParentCollection
1197 return _hasParentCollection;
1201 _hasParentCollection = value;
1205 internal void CheckNullConstraints()
\r
1207 if (_nullConstraintViolation)
\r
1209 for (int i = 0; i < proposed.Length; i++)
\r
1211 if (this[i] == DBNull.Value && !_table.Columns[i].AllowDBNull)
\r
1212 throw new NoNullAllowedException(_nullConstraintMessage);
\r
1214 _nullConstraintViolation = false;
\r
1218 #endregion // Methods