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."));
196 case DataRowVersion.Default:
197 if (editing || rowState == DataRowState.Detached)
198 return proposed[columnIndex];
199 return current[columnIndex];
200 case DataRowVersion.Proposed:
201 return proposed[columnIndex];
202 case DataRowVersion.Current:
203 return current[columnIndex];
204 case DataRowVersion.Original:
205 return original[columnIndex];
207 throw new ArgumentException ();
213 /// Gets or sets all of the values for this row through an array.
216 public object[] ItemArray {
219 if (rowState == DataRowState.Detached)
220 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.");
221 // Accessing deleted rows
222 if (rowState == DataRowState.Deleted)
223 throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
228 if (value.Length > _table.Columns.Count)
229 throw new ArgumentException ();
231 if (rowState == DataRowState.Deleted)
232 throw new DeletedRowInaccessibleException ();
234 object[] newItems = new object[_table.Columns.Count];
236 for (int i = 0; i < _table.Columns.Count; i++) {
238 if (i < value.Length)
243 newItems[i] = SetColumnValue (v, i);
246 bool orginalEditing = editing;
247 if (!orginalEditing) BeginEdit ();
249 if (!orginalEditing) EndEdit ();
253 private object SetColumnValue (object v, int index)
255 object newval = null;
256 DataColumn col = _table.Columns[index];
258 if (_hasParentCollection && col.ReadOnly && v != this[index])
259 throw new ReadOnlyException ();
263 if(col.DefaultValue != DBNull.Value)
265 newval = col.DefaultValue;
267 else if(col.AutoIncrement == true)
269 newval = this [index];
273 if (!col.AllowDBNull)
275 //Constraint violations during data load is raise in DataTable EndLoad
276 this._nullConstraintViolation = true;
277 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
280 newval = DBNull.Value;
283 else if (v == DBNull.Value)
286 if (!col.AllowDBNull)
288 //Constraint violations during data load is raise in DataTable EndLoad
289 this._nullConstraintViolation = true;
290 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
293 newval = DBNull.Value;
297 Type vType = v.GetType(); // data type of value
298 Type cType = col.DataType; // column data type
301 TypeCode typeCode = Type.GetTypeCode(cType);
303 case TypeCode.Boolean :
304 v = Convert.ToBoolean (v);
307 v = Convert.ToByte (v);
310 v = Convert.ToChar (v);
312 case TypeCode.DateTime :
313 v = Convert.ToDateTime (v);
315 case TypeCode.Decimal :
316 v = Convert.ToDecimal (v);
318 case TypeCode.Double :
319 v = Convert.ToDouble (v);
321 case TypeCode.Int16 :
322 v = Convert.ToInt16 (v);
324 case TypeCode.Int32 :
325 v = Convert.ToInt32 (v);
327 case TypeCode.Int64 :
328 v = Convert.ToInt64 (v);
330 case TypeCode.SByte :
331 v = Convert.ToSByte (v);
333 case TypeCode.Single :
334 v = Convert.ToSingle (v);
336 case TypeCode.String :
337 v = Convert.ToString (v);
339 case TypeCode.UInt16 :
340 v = Convert.ToUInt16 (v);
342 case TypeCode.UInt32 :
343 v = Convert.ToUInt32 (v);
345 case TypeCode.UInt64 :
346 v = Convert.ToUInt64 (v);
350 switch(cType.ToString()) {
351 case "System.TimeSpan" :
352 v = (System.TimeSpan) v;
357 case "System.Object" :
358 //v = (System.Object) v;
362 throw new InvalidCastException("Type not supported.");
370 if(col.AutoIncrement == true) {
371 long inc = Convert.ToInt64(v);
372 col.UpdateAutoIncrementValue (inc);
375 col.DataHasBeenSet = true;
380 /// Gets or sets the custom error description for a row.
382 public string RowError {
383 get { return rowError; }
384 set { rowError = value; }
388 /// Gets the current state of the row in regards to its relationship to the
389 /// DataRowCollection.
391 public DataRowState RowState {
392 get { return rowState; }
395 //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
396 //to a Datatable so I added this method. Delete if there is a better way.
397 internal void AttachRow() {
400 rowState = DataRowState.Added;
403 //FIXME?: Couldn't find a way to set the RowState when removing the DataRow
404 //from a Datatable so I added this method. Delete if there is a better way.
405 internal void DetachRow() {
407 _hasParentCollection = false;
408 rowState = DataRowState.Detached;
412 /// Gets the DataTable for which this row has a schema.
414 public DataTable Table {
415 get { return _table; }
419 /// Gets and sets index of row. This is used from
422 internal int XmlRowID {
423 get { return xmlRowID; }
424 set { xmlRowID = value; }
432 /// Commits all the changes made to this row since the last time AcceptChanges was
435 public void AcceptChanges ()
437 EndEdit(); // in case it hasn't been called
439 case DataRowState.Added:
440 case DataRowState.Modified:
441 rowState = DataRowState.Unchanged;
443 case DataRowState.Deleted:
444 _table.Rows.RemoveInternal (this);
447 case DataRowState.Detached:
448 throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
450 // Accept from detached
451 if (original == null)
452 original = new object[_table.Columns.Count];
453 Array.Copy (current, original, _table.Columns.Count);
457 /// Begins an edit operation on a DataRow object.
460 public void BeginEdit ()
462 if (rowState == DataRowState.Deleted)
463 throw new DeletedRowInaccessibleException ();
464 if (!HasVersion (DataRowVersion.Proposed)) {
465 proposed = new object[_table.Columns.Count];
466 Array.Copy (current, proposed, current.Length);
468 //TODO: Suspend validation
473 /// Cancels the current edit on the row.
476 public void CancelEdit ()
480 if (HasVersion (DataRowVersion.Proposed)) {
482 if (rowState == DataRowState.Modified)
483 rowState = DataRowState.Unchanged;
488 /// Clears the errors for the row, including the RowError and errors set with
491 public void ClearErrors ()
493 rowError = String.Empty;
494 columnErrors = new String[_table.Columns.Count];
498 /// Deletes the DataRow.
501 public void Delete ()
503 _table.DeletingDataRow(this, DataRowAction.Delete);
505 case DataRowState.Added:
506 Table.Rows.RemoveInternal (this);
508 case DataRowState.Deleted:
511 // check what to do with child rows
512 CheckChildRows(DataRowAction.Delete);
513 rowState = DataRowState.Deleted;
516 _table.DeletedDataRow(this, DataRowAction.Delete);
519 // check the child rows of this row before deleting the row.
520 private void CheckChildRows(DataRowAction action)
523 // in this method we find the row that this row is in a reltion with them.
524 // in shortly we find all child rows of this row.
525 // then we function according to the DeleteRule of the foriegnkey.
528 // 1. find if this row is attached to dataset.
529 // 2. find if EnforceConstraints is true.
530 // 3. find if there are any constraint on the table that the row is in.
531 if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)
533 foreach (DataTable table in _table.DataSet.Tables)
535 // loop on all constraints of the table.
536 ConstraintCollection constraintsCollection = table.Constraints;
537 for (int i = 0; i < constraintsCollection.Count; i++)
539 ForeignKeyConstraint fk = null;
540 if (constraintsCollection[i] is ForeignKeyConstraint)
542 fk = (ForeignKeyConstraint)constraintsCollection[i];
543 if (fk.RelatedTable == _table)
545 //we create a dummy relation because we do not want to duplicate code of GetChild().
546 // we use the dummy relation to find child rows.
547 DataRelation rel = new DataRelation("dummy", fk.RelatedColumns, fk.Columns, false);
549 if (action == DataRowAction.Delete)
550 rule = fk.DeleteRule;
552 rule = fk.UpdateRule;
553 CheckChildRows(rel, action, rule);
561 private void CheckChildRows(DataRelation rel, DataRowAction action, Rule rule)
563 DataRow[] childRows = GetChildRows(rel);
566 case Rule.Cascade: // delete or change all relted rows.
567 if (childRows != null)
569 for (int j = 0; j < childRows.Length; j++)
571 // if action is delete we delete all child rows
572 if (action == DataRowAction.Delete)
574 if (childRows[j].RowState != DataRowState.Deleted)
575 childRows[j].Delete();
577 // if action is change we change the values in the child row
578 else if (action == DataRowAction.Change)
580 // change only the values in the key columns
581 // set the childcolumn value to the new parent row value
582 for (int k = 0; k < rel.ChildColumns.Length; k++)
583 childRows[j][rel.ChildColumns[k]] = this[rel.ParentColumns[k], DataRowVersion.Proposed];
588 case Rule.None: // throw an exception if there are any child rows.
589 if (childRows != null)
591 for (int j = 0; j < childRows.Length; j++)
593 if (childRows[j].RowState != DataRowState.Deleted)
595 string changeStr = "Cannot change this row because constraints are enforced on relation " + rel.RelationName +", and changing this row will strand child rows.";
596 string delStr = "Cannot delete this row because constraints are enforced on relation " + rel.RelationName +", and deleting this row will strand child rows.";
597 string message = action == DataRowAction.Delete ? delStr : changeStr;
598 throw new InvalidConstraintException(message);
603 case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.
604 if (childRows != null)
606 for (int j = 0; j < childRows.Length; j++)
608 DataRow child = childRows[j];
609 if (childRows[j].RowState != DataRowState.Deleted)
611 //set only the key columns to default
612 for (int k = 0; k < rel.ChildColumns.Length; k++)
613 child[rel.ChildColumns[k]] = rel.ChildColumns[k].DefaultValue;
618 case Rule.SetNull: // set the values in the child row to null.
619 if (childRows != null)
621 for (int j = 0; j < childRows.Length; j++)
623 DataRow child = childRows[j];
624 if (childRows[j].RowState != DataRowState.Deleted)
626 // set only the key columns to DBNull
627 for (int k = 0; k < rel.ChildColumns.Length; k++)
628 child.SetNull(rel.ChildColumns[k]);
638 /// Ends the edit occurring on the row.
641 public void EndEdit ()
643 if (_inChangingEvent)
644 throw new InRowChangingEventException("Cannot call EndEdit inside an OnRowChanging event.");
645 if (rowState == DataRowState.Detached)
651 if (HasVersion (DataRowVersion.Proposed))
653 _inChangingEvent = true;
656 _table.ChangingDataRow(this, DataRowAction.Change);
660 _inChangingEvent = false;
662 if (rowState == DataRowState.Unchanged)
663 rowState = DataRowState.Modified;
665 //Calling next method validates UniqueConstraints
669 if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
670 _table.Rows.ValidateDataRowInternal(this);
678 // check all child rows.
679 CheckChildRows(DataRowAction.Change);
683 _table.ChangedDataRow(this, DataRowAction.Change);
688 /// Gets the child rows of this DataRow using the specified DataRelation.
690 public DataRow[] GetChildRows (DataRelation relation)
692 return GetChildRows (relation, DataRowVersion.Current);
696 /// Gets the child rows of a DataRow using the specified RelationName of a
699 public DataRow[] GetChildRows (string relationName)
701 return GetChildRows (Table.DataSet.Relations[relationName]);
705 /// Gets the child rows of a DataRow using the specified DataRelation, and
708 public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version)
710 if (relation == null)
711 return new DataRow[0];
713 if (this.Table == null || RowState == DataRowState.Detached)
714 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.");
716 if (relation.DataSet != this.Table.DataSet)
717 throw new ArgumentException();
719 // TODO: Caching for better preformance
720 ArrayList rows = new ArrayList();
721 DataColumn[] parentColumns = relation.ParentColumns;
722 DataColumn[] childColumns = relation.ChildColumns;
723 int numColumn = parentColumns.Length;
724 if (HasVersion(version))
726 foreach (DataRow row in relation.ChildTable.Rows)
728 bool allColumnsMatch = false;
729 if (row.HasVersion(DataRowVersion.Default))
731 allColumnsMatch = true;
732 for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt)
734 if (!this[parentColumns[columnCnt], version].Equals(
735 row[childColumns[columnCnt], DataRowVersion.Default]))
737 allColumnsMatch = false;
742 if (allColumnsMatch) rows.Add(row);
745 return rows.ToArray(typeof(DataRow)) as DataRow[];
749 /// Gets the child rows of a DataRow using the specified RelationName of a
750 /// DataRelation, and DataRowVersion.
752 public DataRow[] GetChildRows (string relationName, DataRowVersion version)
754 return GetChildRows (Table.DataSet.Relations[relationName], version);
758 /// Gets the error description of the specified DataColumn.
760 public string GetColumnError (DataColumn column)
762 return GetColumnError (_table.Columns.IndexOf(column));
766 /// Gets the error description for the column specified by index.
768 public string GetColumnError (int columnIndex)
770 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
771 throw new IndexOutOfRangeException ();
773 string retVal = columnErrors[columnIndex];
775 retVal = string.Empty;
780 /// Gets the error description for the column, specified by name.
782 public string GetColumnError (string columnName)
784 return GetColumnError (_table.Columns.IndexOf(columnName));
788 /// Gets an array of columns that have errors.
790 public DataColumn[] GetColumnsInError ()
792 ArrayList dataColumns = new ArrayList ();
794 for (int i = 0; i < columnErrors.Length; i += 1)
796 if (columnErrors[i] != null && columnErrors[i] != String.Empty)
797 dataColumns.Add (_table.Columns[i]);
800 return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));
804 /// Gets the parent row of a DataRow using the specified DataRelation.
806 public DataRow GetParentRow (DataRelation relation)
808 return GetParentRow (relation, DataRowVersion.Current);
812 /// Gets the parent row of a DataRow using the specified RelationName of a
815 public DataRow GetParentRow (string relationName)
817 return GetParentRow (relationName, DataRowVersion.Current);
821 /// Gets the parent row of a DataRow using the specified DataRelation, and
824 public DataRow GetParentRow (DataRelation relation, DataRowVersion version)
826 DataRow[] rows = GetParentRows(relation, version);
827 if (rows.Length == 0) return null;
832 /// Gets the parent row of a DataRow using the specified RelationName of a
833 /// DataRelation, and DataRowVersion.
835 public DataRow GetParentRow (string relationName, DataRowVersion version)
837 return GetParentRow (Table.DataSet.Relations[relationName], version);
841 /// Gets the parent rows of a DataRow using the specified DataRelation.
843 public DataRow[] GetParentRows (DataRelation relation)
845 return GetParentRows (relation, DataRowVersion.Current);
849 /// Gets the parent rows of a DataRow using the specified RelationName of a
852 public DataRow[] GetParentRows (string relationName)
854 return GetParentRows (relationName, DataRowVersion.Current);
858 /// Gets the parent rows of a DataRow using the specified DataRelation, and
861 public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version)
863 // TODO: Caching for better preformance
864 if (relation == null)
865 return new DataRow[0];
867 if (this.Table == null || RowState == DataRowState.Detached)
868 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.");
870 if (relation.DataSet != this.Table.DataSet)
871 throw new ArgumentException();
873 ArrayList rows = new ArrayList();
874 DataColumn[] parentColumns = relation.ParentColumns;
875 DataColumn[] childColumns = relation.ChildColumns;
876 int numColumn = parentColumns.Length;
877 if (HasVersion(version))
879 foreach (DataRow row in relation.ParentTable.Rows)
881 bool allColumnsMatch = false;
882 if (row.HasVersion(DataRowVersion.Default))
884 allColumnsMatch = true;
885 for (int columnCnt = 0; columnCnt < numColumn; columnCnt++)
887 if (!this[childColumns[columnCnt], version].Equals(
888 row[parentColumns[columnCnt], DataRowVersion.Default]))
890 allColumnsMatch = false;
895 if (allColumnsMatch) rows.Add(row);
898 return rows.ToArray(typeof(DataRow)) as DataRow[];
902 /// Gets the parent rows of a DataRow using the specified RelationName of a
903 /// DataRelation, and DataRowVersion.
905 public DataRow[] GetParentRows (string relationName, DataRowVersion version)
907 return GetParentRows (Table.DataSet.Relations[relationName], version);
911 /// Gets a value indicating whether a specified version exists.
913 public bool HasVersion (DataRowVersion version)
917 case DataRowVersion.Default:
918 if (rowState == DataRowState.Deleted)
920 if (rowState == DataRowState.Detached)
921 return proposed != null;
923 case DataRowVersion.Proposed:
924 if (rowState == DataRowState.Deleted)
926 return (proposed != null);
927 case DataRowVersion.Current:
928 if (rowState == DataRowState.Deleted || rowState == DataRowState.Detached)
930 return (current != null);
931 case DataRowVersion.Original:
932 if (rowState == DataRowState.Detached)
934 return (original != null);
940 /// Gets a value indicating whether the specified DataColumn contains a null value.
942 public bool IsNull (DataColumn column)
944 object o = this[column];
945 return (o == null || o == DBNull.Value);
949 /// Gets a value indicating whether the column at the specified index contains a null
952 public bool IsNull (int columnIndex)
954 object o = this[columnIndex];
955 return (o == null || o == DBNull.Value);
959 /// Gets a value indicating whether the named column contains a null value.
961 public bool IsNull (string columnName)
963 object o = this[columnName];
964 return (o == null || o == DBNull.Value);
968 /// Gets a value indicating whether the specified DataColumn and DataRowVersion
969 /// contains a null value.
971 public bool IsNull (DataColumn column, DataRowVersion version)
973 object o = this[column, version];
974 return (o == null || o == DBNull.Value);
978 /// Rejects all changes made to the row since AcceptChanges was last called.
980 public void RejectChanges ()
982 if (RowState == DataRowState.Detached)
983 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.");
984 // If original is null, then nothing has happened since AcceptChanges
985 // was last called. We have no "original" to go back to.
986 if (original != null)
988 Array.Copy (original, current, _table.Columns.Count);
990 _table.ChangedDataRow (this, DataRowAction.Rollback);
994 case DataRowState.Added:
995 _table.Rows.RemoveInternal (this);
997 case DataRowState.Modified:
998 rowState = DataRowState.Unchanged;
1000 case DataRowState.Deleted:
1001 rowState = DataRowState.Unchanged;
1007 // If rows are just loaded via Xml the original values are null.
1008 // So in this case we have to remove all columns.
1009 // FIXME: I'm not realy sure, does this break something else, but
1012 if ((rowState & DataRowState.Added) > 0)
1013 _table.Rows.RemoveInternal (this);
1018 /// Sets the error description for a column specified as a DataColumn.
1020 public void SetColumnError (DataColumn column, string error)
1022 SetColumnError (_table.Columns.IndexOf (column), error);
1026 /// Sets the error description for a column specified by index.
1028 public void SetColumnError (int columnIndex, string error)
1030 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
1031 throw new IndexOutOfRangeException ();
1032 columnErrors[columnIndex] = error;
1036 /// Sets the error description for a column specified by name.
1038 public void SetColumnError (string columnName, string error)
1040 SetColumnError (_table.Columns.IndexOf (columnName), error);
1044 /// Sets the value of the specified DataColumn to a null value.
1046 protected void SetNull (DataColumn column)
1048 this[column] = DBNull.Value;
1052 /// Sets the parent row of a DataRow with specified new parent DataRow.
1055 public void SetParentRow (DataRow parentRow)
1057 SetParentRow(parentRow, null);
1061 /// Sets the parent row of a DataRow with specified new parent DataRow and
1065 public void SetParentRow (DataRow parentRow, DataRelation relation)
1067 if (_table == null || parentRow.Table == null || RowState == DataRowState.Detached)
1068 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.");
1070 if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
1071 throw new ArgumentException();
1074 if (relation == null)
1076 foreach (DataRelation parentRel in _table.ParentRelations)
1078 DataColumn[] childCols = parentRel.ChildKeyConstraint.Columns;
1079 DataColumn[] parentCols = parentRel.ChildKeyConstraint.RelatedColumns;
1081 for (int i = 0; i < parentCols.Length; i++)
1083 if (parentRow == null)
1084 this[childCols[i].Ordinal] = DBNull.Value;
1086 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1093 DataColumn[] childCols = relation.ChildKeyConstraint.Columns;
1094 DataColumn[] parentCols = relation.ChildKeyConstraint.RelatedColumns;
1096 for (int i = 0; i < parentCols.Length; i++)
1098 if (parentRow == null)
1099 this[childCols[i].Ordinal] = DBNull.Value;
1101 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1107 //Copy all values of this DataaRow to the row parameter.
1108 internal void CopyValuesToRow(DataRow row)
1112 throw new ArgumentNullException("row");
1114 throw new ArgumentException("'row' is the same as this object");
1116 DataColumnCollection columns = Table.Columns;
1118 for(int i = 0; i < columns.Count; i++){
1120 string columnName = columns[i].ColumnName;
1121 int index = row.Table.Columns.IndexOf(columnName);
1122 //if a column with the same name exists in both rows copy the values
1124 if (HasVersion(DataRowVersion.Original))
1126 if (row.original == null)
1127 row.original = new object[row.Table.Columns.Count];
1128 row.original[index] = row.SetColumnValue(original[i], index);
1130 if (HasVersion(DataRowVersion.Current))
1132 if (row.current == null)
1133 row.current = new object[row.Table.Columns.Count];
1134 row.current[index] = row.SetColumnValue(current[i], index);
1136 if (HasVersion(DataRowVersion.Proposed))
1138 if (row.proposed == null)
1139 row.proposed = new object[row.Table.Columns.Count];
1140 row.proposed[index] = row.SetColumnValue(proposed[i], index);
1143 //Saving the current value as the column value
1144 row[index] = row.current[index];
1149 row.rowState = RowState;
1150 row.RowError = RowError;
1151 row.columnErrors = columnErrors;
1155 public void CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs args)
1157 // if a column is added we hava to add an additional value the
1158 // the priginal, current and propoed arrays.
1159 // this scenario can happened in merge operation.
1161 if (args.Action == System.ComponentModel.CollectionChangeAction.Add)
1164 if (current != null)
1166 tmp = new object[current.Length + 1];
1167 Array.Copy (current, tmp, current.Length);
1168 tmp[tmp.Length - 1] = DBNull.Value;
1171 if (proposed != null)
1173 tmp = new object[proposed.Length + 1];
1174 Array.Copy (proposed, tmp, proposed.Length);
1175 tmp[tmp.Length - 1] = DBNull.Value;
1178 if(original != null)
1180 tmp = new object[original.Length + 1];
1181 Array.Copy (original, tmp, original.Length);
1182 tmp[tmp.Length - 1] = DBNull.Value;
1189 internal bool IsRowChanged(DataRowState rowState) {
1190 if((RowState & rowState) != 0)
1193 //we need to find if child rows of this row changed.
1194 //if yes - we should return true
1196 // if the rowState is deleted we should get the original version of the row
1197 // else - we should get the current version of the row.
1198 DataRowVersion version = (rowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current;
1199 int count = Table.ChildRelations.Count;
1200 for (int i = 0; i < count; i++){
1201 DataRelation rel = Table.ChildRelations[i];
1202 DataRow[] childRows = GetChildRows(rel, version);
1203 for (int j = 0; j < childRows.Length; j++){
1204 if (childRows[j].IsRowChanged(rowState))
1212 internal bool HasParentCollection
1216 return _hasParentCollection;
1220 _hasParentCollection = value;
1224 internal void CheckNullConstraints()
1226 if (_nullConstraintViolation)
1228 for (int i = 0; i < proposed.Length; i++)
1230 if (this[i] == DBNull.Value && !_table.Columns[i].AllowDBNull)
1231 throw new NoNullAllowedException(_nullConstraintMessage);
1233 _nullConstraintViolation = false;
1237 #endregion // Methods