merging the Mainsoft branch to the trunk
[mono.git] / mcs / class / System.Data / System.Data / DataRow.cs
index 7ec86fcc0264d94d9c70f89853c77b821e4c8bee..66154c183e85978e00bdd193d117bed8bebbbc34 100644 (file)
-//\r
-// System.Data.DataRow.cs\r
-//\r
-// Author:\r
-//   Rodrigo Moya <rodrigo@ximian.com>\r
-//   Daniel Morgan <danmorg@sc.rr.com>\r
-//   Tim Coleman <tim@timcoleman.com>\r
-//   Ville Palo <vi64pa@koti.soon.fi>\r
-//   Alan Tam Siu Lung <Tam@SiuLung.com>\r
-//\r
-// (C) Ximian, Inc 2002\r
-// (C) Daniel Morgan 2002, 2003\r
-// Copyright (C) 2002 Tim Coleman\r
-//\r
-\r
-//\r
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)\r
-//\r
-// Permission is hereby granted, free of charge, to any person obtaining\r
-// a copy of this software and associated documentation files (the\r
-// "Software"), to deal in the Software without restriction, including\r
-// without limitation the rights to use, copy, modify, merge, publish,\r
-// distribute, sublicense, and/or sell copies of the Software, and to\r
-// permit persons to whom the Software is furnished to do so, subject to\r
-// the following conditions:\r
-// \r
-// The above copyright notice and this permission notice shall be\r
-// included in all copies or substantial portions of the Software.\r
-// \r
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-//\r
-\r
-using System;\r
-using System.Collections;\r
-using System.Globalization;\r
-using System.Xml;\r
-\r
-using System.Data.Common;\r
-\r
-namespace System.Data {\r
-       /// <summary>\r
-       /// Represents a row of data in a DataTable.\r
-       /// </summary>\r
-       [Serializable]\r
-       public class DataRow\r
-       {\r
-               #region Fields\r
-\r
-               private DataTable _table;\r
-\r
-               internal int _original = -1;\r
-               internal int _current = -1;\r
-               internal int _proposed = -1;\r
-\r
-               private ArrayList _columnErrors;\r
-               private string rowError;\r
-               internal int xmlRowID = 0;\r
-               internal bool _nullConstraintViolation;\r
-               private string _nullConstraintMessage;\r
-               private bool _hasParentCollection;\r
-               private bool _inChangingEvent;\r
-               private int _rowId;\r
-\r
-               private XmlDataDocument.XmlDataElement mappedElement;\r
-               internal bool _inExpressionEvaluation = false;\r
-\r
-               #endregion // Fields\r
-\r
-               #region Constructors\r
-\r
-               /// <summary>\r
-               /// This member supports the .NET Framework infrastructure and is not intended to be \r
-               /// used directly from your code.\r
-               /// </summary>\r
-               protected internal DataRow (DataRowBuilder builder)\r
-               {\r
-                       _table = builder.Table;\r
-                       // Get the row id from the builder.\r
-                       _rowId = builder._rowId;\r
-\r
-                       rowError = String.Empty;\r
-\r
-                       // create mapped XmlDataElement\r
-                       DataSet ds = _table.DataSet;\r
-                       if (ds != null && ds._xmlDataDocument != null)\r
-                               mappedElement = new XmlDataDocument.XmlDataElement (this, _table.Prefix, _table.TableName, _table.Namespace, ds._xmlDataDocument);\r
-               }\r
-\r
-               internal DataRow(DataTable table,int rowId)\r
-               {\r
-                       _table = table;\r
-                       _rowId = rowId;\r
-               }\r
-\r
-               #endregion // Constructors\r
-\r
-               #region Properties\r
-\r
-               private ArrayList ColumnErrors\r
-               {\r
-                       get {\r
-                               if (_columnErrors == null) {\r
-                                       _columnErrors = new ArrayList();\r
-                               }\r
-                               return _columnErrors;\r
-                       }\r
-\r
-                       set {\r
-                               _columnErrors = value;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets a value indicating whether there are errors in a row.\r
-               /// </summary>\r
-               public bool HasErrors {\r
-                       get {\r
-                               if (RowError != string.Empty)\r
-                                       return true;\r
-\r
-                               foreach(String columnError in ColumnErrors) {\r
-                                       if (columnError != null && columnError != string.Empty) {\r
-                                               return true;\r
-                               }\r
-                               }\r
-                               return false;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets or sets the data stored in the column specified by name.\r
-               /// </summary>\r
-               public object this[string columnName] {\r
-                       get { return this[columnName, DataRowVersion.Default]; }\r
-                       set {\r
-                               int columnIndex = _table.Columns.IndexOf (columnName);\r
-                               if (columnIndex == -1)\r
-                                       throw new IndexOutOfRangeException ();\r
-                               this[columnIndex] = value;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets or sets the data stored in specified DataColumn\r
-               /// </summary>\r
-               public object this[DataColumn column] {\r
-\r
-                       get {\r
-                               return this[column, DataRowVersion.Default];} \r
-                       set {\r
-                               int columnIndex = _table.Columns.IndexOf (column);\r
-                               if (columnIndex == -1)\r
-                                       throw new ArgumentException ("The column does not belong to this table.");\r
-                               this[columnIndex] = value;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets or sets the data stored in column specified by index.\r
-               /// </summary>\r
-               public object this[int columnIndex] {\r
-                       get { return this[columnIndex, DataRowVersion.Default]; }\r
-                       set {\r
-                               if (columnIndex < 0 || columnIndex > _table.Columns.Count)\r
-                                       throw new IndexOutOfRangeException ();\r
-                               if (RowState == DataRowState.Deleted)\r
-                                       throw new DeletedRowInaccessibleException ();\r
-\r
-                               DataColumn column = _table.Columns[columnIndex];\r
-                               _table.ChangingDataColumn (this, column, value);\r
-                               \r
-                               if (value == null && column.DataType != typeof(string)) {\r
-                                       throw new ArgumentException("Cannot set column " + column.ColumnName + " to be null, Please use DBNull instead");\r
-                               }\r
-                               \r
-                               CheckValue (value, column);\r
-\r
-                               bool orginalEditing = Proposed >= 0;\r
-                               if (!orginalEditing) {\r
-                                       BeginEdit ();\r
-                               }\r
-                               \r
-                               column[Proposed] = value;\r
-                               _table.ChangedDataColumn (this, column, value);\r
-                               if (!orginalEditing) {\r
-                                       EndEdit ();\r
-                               }\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the specified version of data stored in the named column.\r
-               /// </summary>\r
-               public object this[string columnName, DataRowVersion version] {\r
-                       get {\r
-                               int columnIndex = _table.Columns.IndexOf (columnName);\r
-                               if (columnIndex == -1)\r
-                                       throw new IndexOutOfRangeException ();\r
-                               return this[columnIndex, version];\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the specified version of data stored in the specified DataColumn.\r
-               /// </summary>\r
-               public object this[DataColumn column, DataRowVersion version] {\r
-                       get {\r
-                               if (column.Table != Table)\r
-                                       throw new ArgumentException ("The column does not belong to this table.");\r
-                               int columnIndex = column.Ordinal;\r
-                               return this[columnIndex, version];\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the data stored in the column, specified by index and version of the data to\r
-               /// retrieve.\r
-               /// </summary>\r
-               public object this[int columnIndex, DataRowVersion version] {\r
-                       get {\r
-                               if (columnIndex < 0 || columnIndex > _table.Columns.Count)\r
-                                       throw new IndexOutOfRangeException ();\r
-                               // Accessing deleted rows\r
-                               if (!_inExpressionEvaluation && RowState == DataRowState.Deleted && version != DataRowVersion.Original)\r
-                                       throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");\r
-                               \r
-                               DataColumn column = _table.Columns[columnIndex];\r
-                               int recordIndex = IndexFromVersion(version);\r
-\r
-                               if (column.Expression != String.Empty) {\r
-                                       object o = column.CompiledExpression.Eval (this);\r
-                                       if (o != null && o != DBNull.Value) {\r
-                                               o = Convert.ChangeType (o, column.DataType);\r
-                                       }\r
-                                       column[recordIndex] = o;\r
-                                       return column[recordIndex];\r
-                               }\r
-\r
-                               if (RowState == DataRowState.Detached && version == DataRowVersion.Default && Proposed < 0)\r
-                                       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.");\r
-                               \r
-                               return column[recordIndex];\r
-                       }\r
-               }\r
-               \r
-               /// <summary>\r
-               /// Gets or sets all of the values for this row through an array.\r
-               /// </summary>\r
-               public object[] ItemArray {\r
-                       get { \r
-                               // row not in table\r
-                               if (RowState == DataRowState.Detached)\r
-                                       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.");\r
-                               // Accessing deleted rows\r
-                               if (RowState == DataRowState.Deleted)\r
-                                       throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");\r
-                               \r
-                               object[] items = new object[_table.Columns.Count];\r
-                               foreach(DataColumn column in _table.Columns) {\r
-                                       items[column.Ordinal] = column[Current];\r
-                               }\r
-                               return items;\r
-                       }\r
-                       set {\r
-                               if (value.Length > _table.Columns.Count)\r
-                                       throw new ArgumentException ();\r
-\r
-                               if (RowState == DataRowState.Deleted)\r
-                                       throw new DeletedRowInaccessibleException ();\r
-                               \r
-                               BeginEdit ();\r
-\r
-                               DataColumnChangeEventArgs e = new DataColumnChangeEventArgs();\r
-                               foreach(DataColumn column in _table.Columns) {\r
-                                       int i = column.Ordinal;\r
-                                       object newVal = (i < value.Length) ? value[i] : null;\r
-\r
-                                       if (newVal == null)\r
-                                               continue;\r
-                                       \r
-                                       e.Initialize(this, column, newVal);\r
-                                       CheckValue (e.ProposedValue, column);\r
-                                       _table.RaiseOnColumnChanging(e);\r
-                                       column[Proposed] = e.ProposedValue;\r
-                                       _table.RaiseOnColumnChanged(e);\r
-                               }\r
-                               \r
-                               EndEdit ();\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the current state of the row in regards to its relationship to the\r
-               /// DataRowCollection.\r
-               /// </summary>\r
-               public DataRowState RowState {\r
-                       get { \r
-                               //return rowState; \r
-                                 if ((Original == -1) && (Current == -1))\r
-                                       {\r
-                                               return DataRowState.Detached;\r
-                                       }\r
-                                       if (Original == Current)\r
-                                       {\r
-                                               return DataRowState.Unchanged;\r
-                                       }\r
-                                       if (Original == -1)\r
-                                       {\r
-                                               return DataRowState.Added;\r
-                                       }\r
-                                       if (Current == -1)\r
-                                       {\r
-                                               return DataRowState.Deleted;\r
-                                       }\r
-                                       return DataRowState.Modified;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the DataTable for which this row has a schema.\r
-               /// </summary>\r
-               public DataTable Table {\r
-                       get { \r
-                               return _table; \r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets and sets index of row. This is used from \r
-               /// XmlDataDocument.\r
-               // </summary>\r
-               internal int XmlRowID {\r
-                       get { \r
-                               return xmlRowID; \r
-                       }\r
-                       set { \r
-                               xmlRowID = value; \r
-                       }\r
-               }\r
-               \r
-               /// <summary>\r
-               /// Gets and sets index of row.\r
-               // </summary>\r
-               internal int RowID {\r
-                       get { \r
-                               return _rowId; \r
-                       }\r
-                       set { \r
-                               _rowId = value; \r
-                       }\r
-               }\r
-\r
-               internal int Original\r
-               {\r
-                       get {\r
-                               return _original;\r
-                       }\r
-                       set {\r
-                               if (Table != null) {\r
-                                       //Table.RecordCache[_original] = null;\r
-                                       Table.RecordCache[value] = this;\r
-                               }\r
-                               _original = value;\r
-                       }\r
-               }\r
-\r
-               internal int Current\r
-               {\r
-                       get {\r
-                               return _current;\r
-                       }\r
-                       set {\r
-                               if (Table != null) {\r
-                                       //Table.RecordCache[_current] = null;\r
-                                       Table.RecordCache[value] = this;\r
-                               }\r
-                               _current = value;\r
-                       }\r
-               }\r
-\r
-               internal int Proposed\r
-               {\r
-                       get {\r
-                               return _proposed;\r
-                       }\r
-                       set {\r
-                               if (Table != null) {\r
-                                       //Table.RecordCache[_proposed] = null;\r
-                                       Table.RecordCache[value] = this;\r
-                               }\r
-                               _proposed = value;\r
-                       }\r
-               }\r
-\r
-               #endregion\r
-\r
-               #region Methods\r
-\r
-               //FIXME?: Couldn't find a way to set the RowState when adding the DataRow\r
-               //to a Datatable so I added this method. Delete if there is a better way.\r
-               internal void AttachRow() {\r
-                       if (Proposed != -1) {\r
-                               if (Current >= 0) {\r
-                                       Table.RecordCache.DisposeRecord(Current);\r
-                               }\r
-                               Current = Proposed;\r
-                               Proposed = -1;\r
-                       }\r
-               }\r
-\r
-               //FIXME?: Couldn't find a way to set the RowState when removing the DataRow\r
-               //from a Datatable so I added this method. Delete if there is a better way.\r
-               internal void DetachRow() {\r
-                       if (Proposed >= 0) {\r
-                               _table.RecordCache.DisposeRecord(Proposed);\r
-                               if (Proposed == Current) {\r
-                                       Current = -1;\r
-                               }\r
-                               if (Proposed == Original) {\r
-                                       Original = -1;\r
-                               }\r
-                               Proposed = -1;\r
-                       }\r
-\r
-                       if (Current >= 0) {\r
-                               _table.RecordCache.DisposeRecord(Current);\r
-                               if (Current == Original) {\r
-                                       Original = -1;\r
-                               }\r
-                               Current = -1;\r
-                       }\r
-\r
-                       if (Original >= 0) {\r
-                               _table.RecordCache.DisposeRecord(Original);\r
-                               Original = -1;\r
-                       }\r
-\r
-                       _rowId = -1;\r
-                       _hasParentCollection = false;\r
-               }\r
-\r
-               internal void ImportRecord(int record)\r
-               {\r
-                       if (HasVersion(DataRowVersion.Proposed)) {\r
-                               Table.RecordCache.DisposeRecord(Proposed);\r
-                       }\r
-\r
-                       Proposed = record;\r
-\r
-                       foreach(DataColumn column in Table.Columns.AutoIncrmentColumns) {\r
-                               column.UpdateAutoIncrementValue(column.DataContainer.GetInt64(Proposed));\r
-                       }\r
-\r
-               }\r
-\r
-               private void CheckValue (object v, DataColumn col) \r
-               {               \r
-                       if (_hasParentCollection && col.ReadOnly) {\r
-                               throw new ReadOnlyException ();\r
-                       }\r
-\r
-                       if (v == null || v == DBNull.Value) {\r
-                               if (col.AllowDBNull || col.AutoIncrement || col.DefaultValue != DBNull.Value) {\r
-                                       return;\r
-                               }\r
-\r
-                               //Constraint violations during data load is raise in DataTable EndLoad\r
-                               this._nullConstraintViolation = true;\r
-                               if (this.Table._duringDataLoad) {\r
-                                       this.Table._nullConstraintViolationDuringDataLoad = true;\r
-                               }\r
-                               _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";\r
-                       \r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets or sets the custom error description for a row.\r
-               /// </summary>\r
-               public string RowError {\r
-                       get { \r
-                               return rowError; \r
-                       }\r
-                       set { \r
-                               rowError = value; \r
-                       }\r
-               }\r
-\r
-               internal int IndexFromVersion(DataRowVersion version)\r
-               {\r
-                       switch (version) {\r
-                               case DataRowVersion.Default:\r
-                                       if (Proposed >= 0)\r
-                                               return Proposed;\r
-\r
-                                       if (Current >= 0)\r
-                                               return Current;\r
-\r
-                                       if (Original < 0)\r
-                                               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.");\r
-\r
-                                       throw new DeletedRowInaccessibleException("Deleted row information cannot be accessed through the row.");\r
-\r
-                               case DataRowVersion.Proposed:\r
-                                       return AssertValidVersionIndex(version, Proposed);\r
-                               case DataRowVersion.Current:\r
-                                       return AssertValidVersionIndex(version, Current);\r
-                               case DataRowVersion.Original:\r
-                                       return AssertValidVersionIndex(version, Original);\r
-                               default:\r
-                                       throw new DataException ("Version must be Original, Current, or Proposed.");\r
-                       }\r
-               }\r
-\r
-               private int AssertValidVersionIndex(DataRowVersion version, int index) {\r
-                       if (index >= 0)\r
-                               return index;\r
-\r
-                       throw new VersionNotFoundException(String.Format("There is no {0} data to accces.", version));\r
-               }\r
-\r
-               internal DataRowVersion VersionFromIndex(int index) {\r
-                       if (index < 0)\r
-                               throw new ArgumentException("Index must not be negative.");\r
-\r
-                       // the order of ifs matters\r
-                       if (index == Current)\r
-                               return DataRowVersion.Current;\r
-                       if (index == Original)\r
-                               return DataRowVersion.Original;\r
-                       if (index == Proposed)\r
-                               return DataRowVersion.Proposed;\r
-\r
-                       throw new ArgumentException(String.Format("The index {0} does not belong to this row.", index)  );\r
-               }\r
-\r
-               internal XmlDataDocument.XmlDataElement DataElement {\r
-                       get { return mappedElement; }\r
-                       set { mappedElement = value; }\r
-               }\r
-\r
-               internal void SetOriginalValue (string columnName, object val)\r
-               {\r
-                       DataColumn column = _table.Columns[columnName];\r
-                       _table.ChangingDataColumn (this, column, val);\r
-                               \r
-                       if (Original < 0 || Original == Current) { \r
-                               Original = Table.RecordCache.NewRecord();\r
-                       }\r
-                       CheckValue (val, column);\r
-                       column[Original] = val;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Commits all the changes made to this row since the last time AcceptChanges was\r
-               /// called.\r
-               /// </summary>\r
-               public void AcceptChanges () \r
-               {\r
-                       EndEdit(); // in case it hasn't been called\r
-                       CheckChildRows(DataRowAction.Commit);\r
-                       switch (RowState) {\r
-                               case DataRowState.Unchanged:\r
-                                       return;\r
-                       case DataRowState.Added:\r
-                       case DataRowState.Modified:\r
-                                       if (Original >= 0) {\r
-                                               Table.RecordCache.DisposeRecord(Original);\r
-                                       }\r
-                                       Original = Current;\r
-                               break;\r
-                       case DataRowState.Deleted:\r
-                               _table.Rows.RemoveInternal (this);\r
-                               DetachRow();\r
-                               break;\r
-                       case DataRowState.Detached:\r
-                               throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Begins an edit operation on a DataRow object.\r
-               /// </summary>\r
-               public void BeginEdit () \r
-               {\r
-                       if (_inChangingEvent)\r
-                                throw new InRowChangingEventException("Cannot call BeginEdit inside an OnRowChanging event.");\r
-                       if (RowState == DataRowState.Deleted)\r
-                               throw new DeletedRowInaccessibleException ();\r
-\r
-                       if (!HasVersion (DataRowVersion.Proposed)) {\r
-                               Proposed = Table.RecordCache.NewRecord();\r
-                               int from = HasVersion(DataRowVersion.Current) ? Current : Table.DefaultValuesRowIndex;\r
-                               for(int i = 0; i < Table.Columns.Count; i++){\r
-                                       DataColumn column = Table.Columns[i];\r
-                                       column.DataContainer.CopyValue(from,Proposed);\r
-                               }\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Cancels the current edit on the row.\r
-               /// </summary>\r
-               public void CancelEdit () \r
-               {\r
-                        if (_inChangingEvent) {\r
-                                throw new InRowChangingEventException("Cannot call CancelEdit inside an OnRowChanging event.");\r
-                        }\r
-\r
-                       if (HasVersion (DataRowVersion.Proposed)) {\r
-                               Table.RecordCache.DisposeRecord(Proposed);\r
-                               Proposed = -1;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Clears the errors for the row, including the RowError and errors set with\r
-               /// SetColumnError.\r
-               /// </summary>\r
-               public void ClearErrors () \r
-               {\r
-                       rowError = String.Empty;\r
-                       ColumnErrors.Clear();\r
-               }\r
-\r
-               /// <summary>\r
-               /// Deletes the DataRow.\r
-               /// </summary>\r
-               public void Delete () \r
-               {\r
-                       _table.DeletingDataRow(this, DataRowAction.Delete);\r
-                       switch (RowState) {\r
-                       case DataRowState.Added:\r
-                               // check what to do with child rows\r
-                               CheckChildRows(DataRowAction.Delete);\r
-                               _table.DeleteRowFromIndexes (this);\r
-                               Table.Rows.RemoveInternal (this);\r
-\r
-                               // if row was in Added state we move it to Detached.\r
-                               DetachRow();\r
-                               break;\r
-                       case DataRowState.Deleted:\r
-                               break;          \r
-                       default:\r
-                               // check what to do with child rows\r
-                               CheckChildRows(DataRowAction.Delete);\r
-                               _table.DeleteRowFromIndexes (this);\r
-                               break;\r
-                       }\r
-                       if (Current >= 0) {\r
-                               if (Current != Original) {\r
-                                       _table.RecordCache.DisposeRecord(Current);\r
-                               }\r
-                               Current = -1;\r
-                       }\r
-                       _table.DeletedDataRow(this, DataRowAction.Delete);\r
-               }\r
-\r
-               // check the child rows of this row before deleting the row.\r
-               private void CheckChildRows(DataRowAction action)\r
-               {\r
-                       \r
-                       // in this method we find the row that this row is in a relation with them.\r
-                       // in shortly we find all child rows of this row.\r
-                       // then we function according to the DeleteRule of the foriegnkey.\r
-\r
-\r
-                       // 1. find if this row is attached to dataset.\r
-                       // 2. find if EnforceConstraints is true.\r
-                       // 3. find if there are any constraint on the table that the row is in.\r
-                       if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)\r
-                       {\r
-                               foreach (DataTable table in _table.DataSet.Tables)\r
-                               {\r
-                                       // loop on all ForeignKeyConstrain of the table.\r
-                                       foreach (Constraint constraint in table.Constraints) {\r
-                                               if (constraint is ForeignKeyConstraint) { \r
-                                                       ForeignKeyConstraint fk = (ForeignKeyConstraint) constraint;\r
-                                                       if (fk.RelatedTable == _table) {\r
-                                                               switch (action) {\r
-                                                                       case DataRowAction.Delete:\r
-                                                                               CheckChildRows(fk, action, fk.DeleteRule);\r
-                                                                               break;\r
-                                                                       case DataRowAction.Commit:\r
-                                                                       case DataRowAction.Rollback:\r
-                                                                               if (fk.AcceptRejectRule != AcceptRejectRule.None)\r
-                                                                                       CheckChildRows(fk, action, Rule.Cascade);\r
-                                                                               break;\r
-                                                                       default:\r
-                                                                               CheckChildRows(fk, action, fk.UpdateRule);\r
-                                                                               break;\r
-                                                               }\r
-                                                       }                       \r
-                                               }                       \r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               private void CheckChildRows(ForeignKeyConstraint fkc, DataRowAction action, Rule rule)\r
-               {                               \r
-                       DataRow[] childRows = GetChildRows(fkc, DataRowVersion.Current);\r
-                       switch (rule)\r
-                       {\r
-                               case Rule.Cascade:  // delete or change all relted rows.\r
-                                       if (childRows != null)\r
-                                       {\r
-                                               for (int j = 0; j < childRows.Length; j++)\r
-                                               {\r
-                                                       // if action is delete we delete all child rows\r
-                                                       switch(action) {\r
-                                                               case DataRowAction.Delete: {\r
-                                                               if (childRows[j].RowState != DataRowState.Deleted)\r
-                                                                       childRows[j].Delete();\r
-\r
-                                                                       break;\r
-                                                       }\r
-                                                       // if action is change we change the values in the child row\r
-                                                               case DataRowAction.Change: {\r
-                                                               // change only the values in the key columns\r
-                                                               // set the childcolumn value to the new parent row value\r
-                                                               for (int k = 0; k < fkc.Columns.Length; k++)\r
-                                                                       childRows[j][fkc.Columns[k]] = this[fkc.RelatedColumns[k], DataRowVersion.Proposed];\r
-\r
-                                                                       break;\r
-                                                               }\r
-\r
-                                                               case DataRowAction.Rollback: {\r
-                                                                       if (childRows[j].RowState != DataRowState.Unchanged)\r
-                                                                               childRows[j].RejectChanges ();\r
-\r
-                                                                       break;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                               case Rule.None: // throw an exception if there are any child rows.\r
-                                       if (childRows != null)\r
-                                       {\r
-                                               for (int j = 0; j < childRows.Length; j++)\r
-                                               {\r
-                                                       if (childRows[j].RowState != DataRowState.Deleted)\r
-                                                       {\r
-                                                               string changeStr = "Cannot change this row because constraints are enforced on relation " + fkc.ConstraintName +", and changing this row will strand child rows.";\r
-                                                               string delStr = "Cannot delete this row because constraints are enforced on relation " + fkc.ConstraintName +", and deleting this row will strand child rows.";\r
-                                                               string message = action == DataRowAction.Delete ? delStr : changeStr;\r
-                                                               throw new InvalidConstraintException(message);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                               case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.\r
-                                       if (childRows != null && childRows.Length > 0) {\r
-                                               int defaultValuesRowIndex = childRows[0].Table.DefaultValuesRowIndex;\r
-                                               foreach(DataRow childRow in childRows) {\r
-                                                       if (childRow.RowState != DataRowState.Deleted) {\r
-                                                               int defaultIdx = childRow.IndexFromVersion(DataRowVersion.Default);\r
-                                                               foreach(DataColumn column in fkc.Columns) {\r
-                                                                       column.DataContainer.CopyValue(defaultValuesRowIndex,defaultIdx);\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                               case Rule.SetNull: // set the values in the child row to null.\r
-                                       if (childRows != null)\r
-                                       {\r
-                                               for (int j = 0; j < childRows.Length; j++)\r
-                                               {\r
-                                                       DataRow child = childRows[j];\r
-                                                       if (childRows[j].RowState != DataRowState.Deleted)\r
-                                                       {\r
-                                                               // set only the key columns to DBNull\r
-                                                               for (int k = 0; k < fkc.Columns.Length; k++)\r
-                                                                       child.SetNull(fkc.Columns[k]);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       break;\r
-                       }\r
-\r
-               }\r
-\r
-               /// <summary>\r
-               /// Ends the edit occurring on the row.\r
-               /// </summary>\r
-               public void EndEdit () \r
-               {\r
-                       if (_inChangingEvent)\r
-                               throw new InRowChangingEventException("Cannot call EndEdit inside an OnRowChanging event.");\r
-\r
-                       if (RowState == DataRowState.Detached)\r
-                               return;\r
-                       \r
-                       if (HasVersion (DataRowVersion.Proposed))\r
-                       {\r
-                               CheckReadOnlyStatus();\r
-\r
-                               _inChangingEvent = true;\r
-                               try\r
-                               {\r
-                                       _table.ChangingDataRow(this, DataRowAction.Change);\r
-                               }\r
-                               finally\r
-                               {\r
-                                       _inChangingEvent = false;\r
-                               }\r
-                               \r
-                               //Calling next method validates UniqueConstraints\r
-                               //and ForeignKeys.\r
-                               bool rowValidated = false;\r
-                               try\r
-                               {\r
-                                       if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad) {\r
-                                               _table.Rows.ValidateDataRowInternal(this);\r
-                                               rowValidated = true;\r
-                                       }\r
-                               }\r
-                               catch (Exception e)\r
-                               {\r
-                                       Table.RecordCache.DisposeRecord(Proposed);\r
-                                       Proposed = -1;\r
-                                       throw e;\r
-                               }\r
-\r
-                                       CheckChildRows(DataRowAction.Change);\r
-                               if (Original != Current) {\r
-                                       Table.RecordCache.DisposeRecord(Current);\r
-                               }\r
-\r
-                               Current = Proposed;\r
-                               Proposed = -1;\r
-\r
-                               if (!rowValidated) {\r
-                                       // keep indexes updated even if there was no need to validate row\r
-                                       foreach(Index index in Table.Indexes) {\r
-                                               index.Update(this,Current); //FIXME: why Current ?!\r
-                                       }\r
-                               }\r
-\r
-                               // Note : row state must not be changed before all the job on indexes finished,\r
-                               // since the indexes works with recods rather than with rows and the decision\r
-                               // which of row records to choose depends on row state.\r
-                               _table.ChangedDataRow(this, DataRowAction.Change);\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the child rows of this DataRow using the specified DataRelation.\r
-               /// </summary>\r
-               public DataRow[] GetChildRows (DataRelation relation) \r
-               {\r
-                       return GetChildRows (relation, DataRowVersion.Default);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the child rows of a DataRow using the specified RelationName of a\r
-               /// DataRelation.\r
-               /// </summary>\r
-               public DataRow[] GetChildRows (string relationName) \r
-               {\r
-                       return GetChildRows (Table.DataSet.Relations[relationName]);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the child rows of a DataRow using the specified DataRelation, and\r
-               /// DataRowVersion.\r
-               /// </summary>\r
-               public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version) \r
-               {\r
-                       if (relation == null)\r
-                               return Table.NewRowArray(0);\r
-\r
-                       if (this.Table == null)\r
-                               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.");\r
-\r
-                       if (relation.DataSet != this.Table.DataSet)\r
-                               throw new ArgumentException();\r
-\r
-                       if (_table != relation.ParentTable)\r
-                               throw new InvalidConstraintException ("GetChildRow requires a row whose Table is " + relation.ParentTable + ", but the specified row's table is " + _table);\r
-\r
-                       if (relation.ChildKeyConstraint != null)\r
-                               return GetChildRows (relation.ChildKeyConstraint, version);\r
-\r
-                       ArrayList rows = new ArrayList();\r
-                       DataColumn[] parentColumns = relation.ParentColumns;\r
-                       DataColumn[] childColumns = relation.ChildColumns;\r
-                       int numColumn = parentColumns.Length;\r
-                       DataRow[] result = null;\r
-\r
-                       int versionIndex = IndexFromVersion(version);\r
-                       int tmpRecord = relation.ChildTable.RecordCache.NewRecord();\r
-\r
-                       try {\r
-                               for (int i = 0; i < numColumn; i++) {\r
-                                       // according to MSDN: the DataType value for both columns must be identical.\r
-                                       childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, versionIndex, tmpRecord);\r
-                               }\r
-\r
-                               Index index = relation.ChildTable.FindIndex(childColumns);\r
-\r
-                               if (index != null) {\r
-                                       int[] records = index.FindAll(tmpRecord);\r
-                                       result = relation.ChildTable.NewRowArray(records.Length);\r
-                                       for(int i=0; i < records.Length; i++) {\r
-                                               result[i] = relation.ChildTable.RecordCache[records[i]];\r
-                                       }\r
-                               }\r
-                               else {\r
-                                       foreach (DataRow row in relation.ChildTable.Rows) {\r
-                                               bool allColumnsMatch = false;\r
-                                               if (row.HasVersion(DataRowVersion.Default)) {\r
-                                                       allColumnsMatch = true;\r
-                                                       int childIndex = row.IndexFromVersion(DataRowVersion.Default);\r
-                                                       for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) {\r
-                                                               if (childColumns[columnCnt].DataContainer.CompareValues(childIndex, tmpRecord) != 0) {\r
-                                                               allColumnsMatch = false;\r
-                                                               break;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       if (allColumnsMatch) rows.Add(row);\r
-                               }\r
-                                       result = relation.ChildTable.NewRowArray(rows.Count);\r
-                                       rows.CopyTo(result, 0);\r
-                               }\r
-                       }\r
-                       finally {\r
-                               relation.ChildTable.RecordCache.DisposeRecord(tmpRecord);\r
-                       }                       \r
-\r
-                       return result;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the child rows of a DataRow using the specified RelationName of a\r
-               /// DataRelation, and DataRowVersion.\r
-               /// </summary>\r
-               public DataRow[] GetChildRows (string relationName, DataRowVersion version) \r
-               {\r
-                       return GetChildRows (Table.DataSet.Relations[relationName], version);\r
-               }\r
-\r
-               private DataRow[] GetChildRows (ForeignKeyConstraint fkc, DataRowVersion version) \r
-               {\r
-                       ArrayList rows = new ArrayList();\r
-                       DataColumn[] parentColumns = fkc.RelatedColumns;\r
-                       DataColumn[] childColumns = fkc.Columns;\r
-                       int numColumn = parentColumns.Length;\r
-\r
-                               Index index = fkc.Index;\r
-\r
-                       int curIndex = IndexFromVersion(version);\r
-                       int tmpRecord = fkc.Table.RecordCache.NewRecord();\r
-                       for (int i = 0; i < numColumn; i++) {\r
-                               // according to MSDN: the DataType value for both columns must be identical.\r
-                               childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, curIndex, tmpRecord);\r
-                       }\r
-\r
-                       try {\r
-                               if (index != null) {\r
-                                       // get the child rows from the index\r
-                                       int[] childRecords = index.FindAll(tmpRecord);\r
-                                       for (int i = 0; i < childRecords.Length; i++) {\r
-                                               rows.Add (childColumns[i].Table.RecordCache[childRecords[i]]);\r
-                                       }\r
-                               }\r
-                               else { // if there is no index we search manualy.\r
-                                               foreach (DataRow row in fkc.Table.Rows) {\r
-                                                       bool allColumnsMatch = false;\r
-                                                       if (row.HasVersion(DataRowVersion.Default)) {\r
-                                                               allColumnsMatch = true;\r
-                                                               int childIndex = row.IndexFromVersion(DataRowVersion.Default);\r
-                                                               for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) {\r
-                                                                       if (childColumns[columnCnt].DataContainer.CompareValues(childIndex, tmpRecord) != 0) {\r
-                                                                               allColumnsMatch = false;\r
-                                                                               break;\r
-                                                                       }\r
-                                                               }\r
-                                                       }\r
-                                                       if (allColumnsMatch) {\r
-                                                               rows.Add(row);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                       }\r
-                                       finally {\r
-                                               fkc.Table.RecordCache.DisposeRecord(tmpRecord);\r
-                                       }\r
-\r
-                       DataRow[] result = fkc.Table.NewRowArray(rows.Count);\r
-                       rows.CopyTo(result, 0);\r
-                       return result;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the error description of the specified DataColumn.\r
-               /// </summary>\r
-               public string GetColumnError (DataColumn column) \r
-               {\r
-                       if (column == null)\r
-                               throw new ArgumentNullException("column");\r
-\r
-                       int index = _table.Columns.IndexOf(column);\r
-                       if (index < 0)\r
-                               throw new ArgumentException(String.Format("Column '{0}' does not belong to table {1}.", column.ColumnName, Table.TableName));\r
-\r
-                       return GetColumnError (index);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the error description for the column specified by index.\r
-               /// </summary>\r
-               public string GetColumnError (int columnIndex) \r
-               {\r
-                       if (columnIndex < 0 || columnIndex >= Table.Columns.Count)\r
-                               throw new IndexOutOfRangeException ();\r
-\r
-                       string retVal = null;\r
-                       if (columnIndex < ColumnErrors.Count) {\r
-                               retVal = (String) ColumnErrors[columnIndex];\r
-                       }\r
-                       return (retVal != null) ? retVal : String.Empty;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the error description for the column, specified by name.\r
-               /// </summary>\r
-               public string GetColumnError (string columnName) \r
-               {\r
-                       return GetColumnError (_table.Columns.IndexOf(columnName));\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets an array of columns that have errors.\r
-               /// </summary>\r
-               public DataColumn[] GetColumnsInError () \r
-               {\r
-                       ArrayList dataColumns = new ArrayList ();\r
-\r
-                       int columnOrdinal = 0;\r
-                       foreach(String columnError in ColumnErrors) {\r
-                               if (columnError != null && columnError != String.Empty) {\r
-                                       dataColumns.Add (_table.Columns[columnOrdinal]);\r
-                               }\r
-                               columnOrdinal++;\r
-                       }\r
-\r
-                       return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent row of a DataRow using the specified DataRelation.\r
-               /// </summary>\r
-               public DataRow GetParentRow (DataRelation relation) \r
-               {\r
-                       return GetParentRow (relation, DataRowVersion.Default);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent row of a DataRow using the specified RelationName of a\r
-               /// DataRelation.\r
-               /// </summary>\r
-               public DataRow GetParentRow (string relationName) \r
-               {\r
-                       return GetParentRow (relationName, DataRowVersion.Default);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent row of a DataRow using the specified DataRelation, and\r
-               /// DataRowVersion.\r
-               /// </summary>\r
-               public DataRow GetParentRow (DataRelation relation, DataRowVersion version) \r
-               {\r
-                       DataRow[] rows = GetParentRows(relation, version);\r
-                       if (rows.Length == 0) return null;\r
-                       return rows[0];\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent row of a DataRow using the specified RelationName of a \r
-               /// DataRelation, and DataRowVersion.\r
-               /// </summary>\r
-               public DataRow GetParentRow (string relationName, DataRowVersion version) \r
-               {\r
-                       return GetParentRow (Table.DataSet.Relations[relationName], version);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent rows of a DataRow using the specified DataRelation.\r
-               /// </summary>\r
-               public DataRow[] GetParentRows (DataRelation relation) \r
-               {\r
-                       return GetParentRows (relation, DataRowVersion.Default);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent rows of a DataRow using the specified RelationName of a \r
-               /// DataRelation.\r
-               /// </summary>\r
-               public DataRow[] GetParentRows (string relationName) \r
-               {\r
-                       return GetParentRows (relationName, DataRowVersion.Default);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent rows of a DataRow using the specified DataRelation, and\r
-               /// DataRowVersion.\r
-               /// </summary>\r
-               public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version) \r
-               {\r
-                       // TODO: Caching for better preformance\r
-                       if (relation == null)\r
-                               return Table.NewRowArray(0);\r
-\r
-                       if (this.Table == null)\r
-                               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.");\r
-\r
-                       if (relation.DataSet != this.Table.DataSet)\r
-                               throw new ArgumentException();\r
-\r
-                       if (_table != relation.ChildTable)\r
-                               throw new InvalidConstraintException ("GetParentRows requires a row whose Table is " + relation.ChildTable + ", but the specified row's table is " + _table);\r
-\r
-                       ArrayList rows = new ArrayList();\r
-                       DataColumn[] parentColumns = relation.ParentColumns;\r
-                       DataColumn[] childColumns = relation.ChildColumns;\r
-                       int numColumn = parentColumns.Length;\r
-\r
-                       int curIndex = IndexFromVersion(version);\r
-                                       int tmpRecord = relation.ParentTable.RecordCache.NewRecord();\r
-                                               for (int i = 0; i < numColumn; i++) {\r
-                                                       // according to MSDN: the DataType value for both columns must be identical.\r
-                                                       parentColumns[i].DataContainer.CopyValue(childColumns[i].DataContainer, curIndex, tmpRecord);\r
-                                               }\r
-\r
-                       try {\r
-                               Index index = relation.ParentTable.FindIndex(parentColumns);\r
-                               if (index != null) { // get the parent rows from the index\r
-                                       int[] parentRecords = index.FindAll(tmpRecord);\r
-                                       for (int i = 0; i < parentRecords.Length; i++) {\r
-                                               rows.Add (parentColumns[i].Table.RecordCache[parentRecords[i]]);\r
-                                       }\r
-                               }\r
-                               else { // no index so we have to search manualy.\r
-                                               foreach (DataRow row in relation.ParentTable.Rows) {\r
-                                                       bool allColumnsMatch = false;\r
-                                                       if (row.HasVersion(DataRowVersion.Default)) {\r
-                                                               allColumnsMatch = true;\r
-                                                               int parentIndex = row.IndexFromVersion(DataRowVersion.Default);\r
-                                                               for (int columnCnt = 0; columnCnt < numColumn; columnCnt++) {\r
-                                                                       if (parentColumns[columnCnt].DataContainer.CompareValues(parentIndex, tmpRecord) != 0) {\r
-                                                                               allColumnsMatch = false;\r
-                                                                               break;\r
-                                                                       }\r
-                                                               }\r
-                                                       }\r
-                                                       if (allColumnsMatch) {\r
-                                                               rows.Add(row);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                       }\r
-                                       finally {\r
-                                               relation.ParentTable.RecordCache.DisposeRecord(tmpRecord);\r
-                                       }\r
-\r
-                       DataRow[] result = relation.ParentTable.NewRowArray(rows.Count);\r
-                       rows.CopyTo(result, 0);\r
-                       return result;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets the parent rows of a DataRow using the specified RelationName of a \r
-               /// DataRelation, and DataRowVersion.\r
-               /// </summary>\r
-               public DataRow[] GetParentRows (string relationName, DataRowVersion version) \r
-               {\r
-                       return GetParentRows (Table.DataSet.Relations[relationName], version);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets a value indicating whether a specified version exists.\r
-               /// </summary>\r
-               public bool HasVersion (DataRowVersion version) \r
-               {\r
-                       switch (version) {\r
-                               case DataRowVersion.Default:\r
-                                       return (Proposed >= 0 || Current >= 0);\r
-                               case DataRowVersion.Proposed:\r
-                                       return Proposed >= 0;\r
-                               case DataRowVersion.Current:\r
-                                       return Current >= 0;\r
-                               case DataRowVersion.Original:\r
-                                       return Original >= 0;\r
-                               default:\r
-                                       return IndexFromVersion(version) >= 0;\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets a value indicating whether the specified DataColumn contains a null value.\r
-               /// </summary>\r
-               public bool IsNull (DataColumn column) \r
-               {\r
-                       return IsNull(column, DataRowVersion.Default);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets a value indicating whether the column at the specified index contains a null\r
-               /// value.\r
-               /// </summary>\r
-               public bool IsNull (int columnIndex) \r
-               {\r
-                       return IsNull(Table.Columns[columnIndex]);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets a value indicating whether the named column contains a null value.\r
-               /// </summary>\r
-               public bool IsNull (string columnName) \r
-               {\r
-                       return IsNull(Table.Columns[columnName]);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Gets a value indicating whether the specified DataColumn and DataRowVersion\r
-               /// contains a null value.\r
-               /// </summary>\r
-               public bool IsNull (DataColumn column, DataRowVersion version) \r
-               {\r
-                       object o = this[column,version];\r
-                       return column.DataContainer.IsNull(IndexFromVersion(version));\r
-               }\r
-\r
-               /// <summary>\r
-               /// Returns a value indicating whether all of the row columns specified contain a null value.\r
-               /// </summary>\r
-               internal bool IsNullColumns(DataColumn[] columns)\r
-               {\r
-                       bool allNull = true;\r
-                       for (int i = 0; i < columns.Length; i++) \r
-                       {\r
-                               if (!IsNull(columns[i])) \r
-                               {\r
-                                       allNull = false;\r
-                                       break;\r
-                               }\r
-                       }\r
-                       return allNull;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Rejects all changes made to the row since AcceptChanges was last called.\r
-               /// </summary>\r
-               public void RejectChanges () \r
-               {\r
-                       if (RowState == DataRowState.Detached)\r
-                               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.");\r
-                       // If original is null, then nothing has happened since AcceptChanges\r
-                       // was last called.  We have no "original" to go back to.\r
-                       if (HasVersion(DataRowVersion.Original)) {\r
-                               if (Current >= 0 && Current != Original) {\r
-                                       Table.RecordCache.DisposeRecord(Current);\r
-                               }\r
-                               CheckChildRows(DataRowAction.Rollback);\r
-\r
-                               Current = Original;\r
-                              \r
-                               _table.ChangedDataRow (this, DataRowAction.Rollback);\r
-                               CancelEdit ();\r
-                               switch (RowState)\r
-                               {\r
-                                       case DataRowState.Added:\r
-                                               _table.DeleteRowFromIndexes (this);\r
-                                               _table.Rows.RemoveInternal (this);\r
-                                               break;\r
-                                       case DataRowState.Modified:\r
-                                               if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)\r
-                                                       _table.Rows.ValidateDataRowInternal(this);\r
-                                               break;\r
-                                       case DataRowState.Deleted:\r
-                                               if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)\r
-                                                       _table.Rows.ValidateDataRowInternal(this);\r
-                                               break;\r
-                               } \r
-                               \r
-                       }                       \r
-                       else {\r
-                               // If rows are just loaded via Xml the original values are null.\r
-                               // So in this case we have to remove all columns.\r
-                               // FIXME: I'm not realy sure, does this break something else, but\r
-                               // if so: FIXME ;)\r
-                               \r
-                               if ((RowState & DataRowState.Added) > 0)\r
-                               {\r
-                                       _table.DeleteRowFromIndexes (this);\r
-                                       _table.Rows.RemoveInternal (this);\r
-                                       // if row was in Added state we move it to Detached.\r
-                                       DetachRow();\r
-                               }\r
-                       }\r
-               }\r
-\r
-               /// <summary>\r
-               /// Sets the error description for a column specified as a DataColumn.\r
-               /// </summary>\r
-               public void SetColumnError (DataColumn column, string error) \r
-               {\r
-                       SetColumnError (_table.Columns.IndexOf (column), error);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Sets the error description for a column specified by index.\r
-               /// </summary>\r
-               public void SetColumnError (int columnIndex, string error) \r
-               {\r
-                       if (columnIndex < 0 || columnIndex >= Table.Columns.Count)\r
-                               throw new IndexOutOfRangeException ();\r
-\r
-                       while(ColumnErrors.Count < columnIndex) {\r
-                               ColumnErrors.Add(null);\r
-                       }\r
-                       ColumnErrors.Add(error);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Sets the error description for a column specified by name.\r
-               /// </summary>\r
-               public void SetColumnError (string columnName, string error) \r
-               {\r
-                       SetColumnError (_table.Columns.IndexOf (columnName), error);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Sets the value of the specified DataColumn to a null value.\r
-               /// </summary>\r
-               protected void SetNull (DataColumn column) \r
-               {\r
-                       this[column] = DBNull.Value;\r
-               }\r
-\r
-               /// <summary>\r
-               /// Sets the parent row of a DataRow with specified new parent DataRow.\r
-               /// </summary>\r
-               public void SetParentRow (DataRow parentRow) \r
-               {\r
-                       SetParentRow(parentRow, null);\r
-               }\r
-\r
-               /// <summary>\r
-               /// Sets the parent row of a DataRow with specified new parent DataRow and\r
-               /// DataRelation.\r
-               /// </summary>\r
-               public void SetParentRow (DataRow parentRow, DataRelation relation) \r
-               {\r
-                       if (_table == null || parentRow.Table == null)\r
-                               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.");\r
-\r
-                       if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)\r
-                               throw new ArgumentException();\r
-                       \r
-                       BeginEdit();\r
-\r
-                       IEnumerable relations; \r
-                       if (relation == null) {\r
-                               relations = _table.ParentRelations;\r
-                       }\r
-                       else {\r
-                               relations = new DataRelation[] { relation };\r
-                       }\r
-\r
-                       foreach (DataRelation rel in relations)\r
-                       {\r
-                               DataColumn[] childCols = rel.ChildColumns;\r
-                               DataColumn[] parentCols = rel.ParentColumns;\r
-                               \r
-                               for (int i = 0; i < parentCols.Length; i++)\r
-                               {\r
-                                       if (parentRow == null) {\r
-                                               childCols[i].DataContainer[Proposed] = DBNull.Value;\r
-                                       }\r
-                                       else {\r
-                                               int defaultIdx = parentRow.IndexFromVersion(DataRowVersion.Default);\r
-                                               childCols[i].DataContainer.CopyValue(parentCols[i].DataContainer,defaultIdx,Proposed);\r
-                                       }\r
-                               }\r
-                               \r
-                       }\r
-\r
-                       EndEdit();\r
-               }\r
-               \r
-               //Copy all values of this DataRow to the row parameter.\r
-               internal void CopyValuesToRow(DataRow row)\r
-               {\r
-                       if (row == null)\r
-                               throw new ArgumentNullException("row");\r
-                       if (row == this)\r
-                               throw new ArgumentException("'row' is the same as this object");\r
-\r
-                       foreach(DataColumn column in Table.Columns) {\r
-                               DataColumn targetColumn = row.Table.Columns[column.ColumnName];\r
-                               //if a column with the same name exists in both rows copy the values\r
-                               if(targetColumn != null) {\r
-                                       int index = targetColumn.Ordinal;\r
-                                       if (HasVersion(DataRowVersion.Original)) {\r
-                                               if (row.Original < 0) {\r
-                                                       row.Original = row.Table.RecordCache.NewRecord();\r
-                                               }\r
-                                               object val = column[Original];\r
-                                               row.CheckValue(val, targetColumn);\r
-                                               targetColumn[row.Original] = val;\r
-                                       }\r
-                                       else {\r
-                                               if (row.Original > 0) {\r
-                                                       row.Table.RecordCache.DisposeRecord(row.Original);\r
-                                                       row.Original = -1;\r
-                                               }\r
-                                       }\r
-\r
-                                       if (HasVersion(DataRowVersion.Current)) {\r
-                                               if (row.Current < 0) {\r
-                                                       row.Current = row.Table.RecordCache.NewRecord();\r
-                                               }\r
-                                               object val = column[Current];\r
-                                               row.CheckValue(val, targetColumn);\r
-                                               targetColumn[row.Current] = val;\r
-                                       }\r
-                                       else {\r
-                                               if (row.Current > 0) {\r
-                                                       row.Table.RecordCache.DisposeRecord(row.Current);\r
-                                                       row.Current = -1;\r
-                                               }\r
-                                       }\r
-\r
-                                       if (HasVersion(DataRowVersion.Proposed)) {\r
-                                               if (row.Proposed < 0) {\r
-                                                       row.Proposed = row.Table.RecordCache.NewRecord();\r
-                                               }\r
-                                               object val = column[row.Proposed];\r
-                                               row.CheckValue(val, targetColumn);\r
-                                               targetColumn[row.Proposed] = val;\r
-                                       }\r
-                                       else {\r
-                                               if (row.Proposed > 0) {\r
-                                                       row.Table.RecordCache.DisposeRecord(row.Proposed);\r
-                                                       row.Proposed = -1;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       if (HasErrors) {\r
-                               CopyErrors(row);\r
-                       }\r
-               }\r
-\r
-               internal void CopyErrors(DataRow row)\r
-               {\r
-                       row.RowError = RowError;\r
-                       DataColumn[] errorColumns = GetColumnsInError();\r
-                       foreach(DataColumn col in errorColumns) {\r
-                               DataColumn targetColumn = row.Table.Columns[col.ColumnName];\r
-                               row.SetColumnError(targetColumn,GetColumnError(col));\r
-                       }\r
-               }\r
-\r
-               internal bool IsRowChanged(DataRowState rowState) {\r
-                       if((RowState & rowState) != 0)\r
-                               return true;\r
-\r
-                       //we need to find if child rows of this row changed.\r
-                       //if yes - we should return true\r
-\r
-                       // if the rowState is deleted we should get the original version of the row\r
-                       // else - we should get the current version of the row.\r
-                       DataRowVersion version = (rowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current;\r
-                       int count = Table.ChildRelations.Count;\r
-                       for (int i = 0; i < count; i++){\r
-                               DataRelation rel = Table.ChildRelations[i];\r
-                               DataRow[] childRows = GetChildRows(rel, version);\r
-                               for (int j = 0; j < childRows.Length; j++){\r
-                                       if (childRows[j].IsRowChanged(rowState))\r
-                                               return true;\r
-                               }\r
-                       }\r
-\r
-                       return false;\r
-               }\r
-\r
-               internal bool HasParentCollection\r
-               {\r
-                       get\r
-                       {\r
-                               return _hasParentCollection;\r
-                       }\r
-                       set\r
-                       {\r
-                               _hasParentCollection = value;\r
-                       }\r
-               }\r
-\r
-               internal void CheckNullConstraints()\r
-               {\r
-                       if (_nullConstraintViolation) {\r
-                               if (HasVersion(DataRowVersion.Proposed)) {\r
-                                       foreach(DataColumn column in Table.Columns) {\r
-                                               if (IsNull(column) && !column.AllowDBNull) {\r
-                                                       throw new NoNullAllowedException(_nullConstraintMessage);\r
-                                       }\r
-                               }\r
-                               }\r
-                               _nullConstraintViolation = false;\r
-                       }\r
-               }\r
-               \r
-               internal void CheckReadOnlyStatus() {\r
-                               int defaultIdx = IndexFromVersion(DataRowVersion.Default); \r
-                               foreach(DataColumn column in Table.Columns) {\r
-                               if ((column.DataContainer.CompareValues(defaultIdx,Proposed) != 0) && column.ReadOnly) {\r
-                                       throw new ReadOnlyException();\r
-                        }\r
-                }\r
-                       }                       \r
-       \r
-               #endregion // Methods\r
-       }\r
-}\r
+//
+// System.Data.DataRow.cs
+//
+// Author:
+//   Rodrigo Moya <rodrigo@ximian.com>
+//   Daniel Morgan <danmorg@sc.rr.com>
+//   Tim Coleman <tim@timcoleman.com>
+//   Ville Palo <vi64pa@koti.soon.fi>
+//   Alan Tam Siu Lung <Tam@SiuLung.com>
+//   Sureshkumar T <tsureshkumar@novell.com>
+//
+// (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002, 2003
+// Copyright (C) 2002 Tim Coleman
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Data.Common;
+using System.Collections;
+using System.Globalization;
+using System.Xml;
+
+using System.Data.Common;
+
+namespace System.Data {
+       /// <summary>
+       /// Represents a row of data in a DataTable.
+       /// </summary>
+       [Serializable]
+       public class DataRow
+       {
+               #region Fields
+
+               private DataTable _table;
+
+               internal int _original = -1;
+               internal int _current = -1;
+               internal int _proposed = -1;
+
+               private ArrayList _columnErrors;
+               private string rowError;
+               internal int xmlRowID = 0;
+               internal bool _nullConstraintViolation;
+               private string _nullConstraintMessage;
+               private bool _hasParentCollection;
+               private bool _inChangingEvent;
+               private int _rowId;
+
+               private XmlDataDocument.XmlDataElement mappedElement;
+               internal bool _inExpressionEvaluation = false;
+
+               #endregion // Fields
+
+               #region Constructors
+
+               /// <summary>
+               /// This member supports the .NET Framework infrastructure and is not intended to be 
+               /// used directly from your code.
+               /// </summary>
+               protected internal DataRow (DataRowBuilder builder)
+               {
+                       _table = builder.Table;
+                       // Get the row id from the builder.
+                       _rowId = builder._rowId;
+
+                       rowError = String.Empty;
+
+                       // create mapped XmlDataElement
+                       DataSet ds = _table.DataSet;
+                       if (ds != null && ds._xmlDataDocument != null)
+                               mappedElement = new XmlDataDocument.XmlDataElement (this, _table.Prefix, _table.TableName, _table.Namespace, ds._xmlDataDocument);
+               }
+
+               internal DataRow(DataTable table,int rowId)
+               {
+                       _table = table;
+                       _rowId = rowId;
+               }
+
+               #endregion // Constructors
+
+               #region Properties
+
+               private ArrayList ColumnErrors
+               {
+                       get {
+                               if (_columnErrors == null) {
+                                       _columnErrors = new ArrayList();
+                               }
+                               return _columnErrors;
+                       }
+
+                       set {
+                               _columnErrors = value;
+                       }
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether there are errors in a row.
+               /// </summary>
+               public bool HasErrors {
+                       get {
+                               if (RowError != string.Empty)
+                                       return true;
+
+                               foreach(String columnError in ColumnErrors) {
+                                       if (columnError != null && columnError != string.Empty) {
+                                               return true;
+                               }
+                               }
+                               return false;
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the data stored in the column specified by name.
+               /// </summary>
+               public object this[string columnName] {
+                       get { return this[columnName, DataRowVersion.Default]; }
+                       set {
+                               int columnIndex = _table.Columns.IndexOf (columnName);
+                               if (columnIndex == -1)
+                                       throw new IndexOutOfRangeException ();
+                               this[columnIndex] = value;
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the data stored in specified DataColumn
+               /// </summary>
+               public object this[DataColumn column] {
+
+                       get {
+                               return this[column, DataRowVersion.Default];} 
+                       set {
+                               int columnIndex = _table.Columns.IndexOf (column);
+                               if (columnIndex == -1)
+                                       throw new ArgumentException ("The column does not belong to this table.");
+                               this[columnIndex] = value;
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the data stored in column specified by index.
+               /// </summary>
+               public object this[int columnIndex] {
+                       get { return this[columnIndex, DataRowVersion.Default]; }
+                       set {
+                               if (columnIndex < 0 || columnIndex > _table.Columns.Count)
+                                       throw new IndexOutOfRangeException ();
+                               if (RowState == DataRowState.Deleted)
+                                       throw new DeletedRowInaccessibleException ();
+
+                               DataColumn column = _table.Columns[columnIndex];
+                               _table.ChangingDataColumn (this, column, value);
+                               
+                               if (value == null && column.DataType != typeof(string)) {
+                                       throw new ArgumentException("Cannot set column " + column.ColumnName + " to be null, Please use DBNull instead");
+                               }
+                               
+                               CheckValue (value, column);
+
+                               bool orginalEditing = Proposed >= 0;
+                               if (!orginalEditing) {
+                                       BeginEdit ();
+                               }
+                               
+                               column[Proposed] = value;
+                               _table.ChangedDataColumn (this, column, value);
+                               if (!orginalEditing) {
+                                       EndEdit ();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets the specified version of data stored in the named column.
+               /// </summary>
+               public object this[string columnName, DataRowVersion version] {
+                       get {
+                               int columnIndex = _table.Columns.IndexOf (columnName);
+                               if (columnIndex == -1)
+                                       throw new IndexOutOfRangeException ();
+                               return this[columnIndex, version];
+                       }
+               }
+
+               /// <summary>
+               /// Gets the specified version of data stored in the specified DataColumn.
+               /// </summary>
+               public object this[DataColumn column, DataRowVersion version] {
+                       get {
+                               if (column.Table != Table)
+                                       throw new ArgumentException ("The column does not belong to this table.");
+                               int columnIndex = column.Ordinal;
+                               return this[columnIndex, version];
+                       }
+               }
+
+                /// <summary>
+                /// Set a value for the column into the offset specified by the version.<br>
+                /// If the value is auto increment or null, necessary auto increment value
+                /// or the default value will be used.
+                /// </summary>
+                internal void SetValue (int column, object value, int version)
+                {
+                        DataColumn dc = Table.Columns[column];
+
+                        if (value == null && ! dc.AutoIncrement) // set default value / auto increment
+                                value = dc.DefaultValue;
+
+                       Table.ChangingDataColumn (this, dc, value);     
+                        CheckValue (value, dc);
+                        if ( ! dc.AutoIncrement)
+                                dc [version] = value;
+                        else if (_proposed >= 0 && _proposed != version) // proposed holds the AI
+                                dc [version] = dc [_proposed];
+                }
+
+               /// <summary>
+               /// Gets the data stored in the column, specified by index and version of the data to
+               /// retrieve.
+               /// </summary>
+               public object this[int columnIndex, DataRowVersion version] {
+                       get {
+                               if (columnIndex < 0 || columnIndex > _table.Columns.Count)
+                                       throw new IndexOutOfRangeException ();
+                               // Accessing deleted rows
+                               if (!_inExpressionEvaluation && RowState == DataRowState.Deleted && version != DataRowVersion.Original)
+                                       throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
+                               
+                               DataColumn column = _table.Columns[columnIndex];
+                               int recordIndex = IndexFromVersion(version);
+
+                               if (column.Expression != String.Empty) {
+                                       object o = column.CompiledExpression.Eval (this);
+                                       if (o != null && o != DBNull.Value) {
+                                               o = Convert.ChangeType (o, column.DataType);
+                                       }
+                                       column[recordIndex] = o;
+                                       return column[recordIndex];
+                               }
+
+                               if (RowState == DataRowState.Detached && version == DataRowVersion.Default && Proposed < 0)
+                                       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.");
+                               
+                               return column[recordIndex];
+                       }
+               }
+               
+               /// <summary>
+               /// Gets or sets all of the values for this row through an array.
+               /// </summary>
+               public object[] ItemArray {
+                       get { 
+                               // row not in table
+                               if (RowState == DataRowState.Detached)
+                                       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.");
+                               // Accessing deleted rows
+                               if (RowState == DataRowState.Deleted)
+                                       throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
+                               
+                               object[] items = new object[_table.Columns.Count];
+                               foreach(DataColumn column in _table.Columns) {
+                                       items[column.Ordinal] = column[Current];
+                               }
+                               return items;
+                       }
+                       set {
+                               if (value.Length > _table.Columns.Count)
+                                       throw new ArgumentException ();
+
+                               if (RowState == DataRowState.Deleted)
+                                       throw new DeletedRowInaccessibleException ();
+                               
+                               BeginEdit ();
+
+                               DataColumnChangeEventArgs e = new DataColumnChangeEventArgs();
+                               foreach(DataColumn column in _table.Columns) {
+                                       int i = column.Ordinal;
+                                       object newVal = (i < value.Length) ? value[i] : null;
+
+                                       if (newVal == null)
+                                               continue;
+                                       
+                                       e.Initialize(this, column, newVal);
+                                       CheckValue (e.ProposedValue, column);
+                                       _table.RaiseOnColumnChanging(e);
+                                       column[Proposed] = e.ProposedValue;
+                                       _table.RaiseOnColumnChanged(e);
+                               }
+                               
+                               EndEdit ();
+                       }
+               }
+
+               /// <summary>
+               /// Gets the current state of the row in regards to its relationship to the
+               /// DataRowCollection.
+               /// </summary>
+               public DataRowState RowState {
+                       get { 
+                               //return rowState; 
+                                 if ((Original == -1) && (Current == -1))
+                                       {
+                                               return DataRowState.Detached;
+                                       }
+                                       if (Original == Current)
+                                       {
+                                               return DataRowState.Unchanged;
+                                       }
+                                       if (Original == -1)
+                                       {
+                                               return DataRowState.Added;
+                                       }
+                                       if (Current == -1)
+                                       {
+                                               return DataRowState.Deleted;
+                                       }
+                                       return DataRowState.Modified;
+                       }
+               }
+
+               /// <summary>
+               /// Gets the DataTable for which this row has a schema.
+               /// </summary>
+               public DataTable Table {
+                       get { 
+                               return _table; 
+                       }
+               }
+
+               /// <summary>
+               /// Gets and sets index of row. This is used from 
+               /// XmlDataDocument.
+               // </summary>
+               internal int XmlRowID {
+                       get { 
+                               return xmlRowID; 
+                       }
+                       set { 
+                               xmlRowID = value; 
+                       }
+               }
+               
+               /// <summary>
+               /// Gets and sets index of row.
+               // </summary>
+               internal int RowID {
+                       get { 
+                               return _rowId; 
+                       }
+                       set { 
+                               _rowId = value; 
+                       }
+               }
+
+               internal int Original
+               {
+                       get {
+                               return _original;
+                       }
+                       set {
+                               if (Table != null) {
+                                       //Table.RecordCache[_original] = null;
+                                       Table.RecordCache[value] = this;
+                               }
+                               _original = value;
+                       }
+               }
+
+               internal int Current
+               {
+                       get {
+                               return _current;
+                       }
+                       set {
+                               if (Table != null) {
+                                       //Table.RecordCache[_current] = null;
+                                       Table.RecordCache[value] = this;
+                               }
+                               _current = value;
+                       }
+               }
+
+               internal int Proposed
+               {
+                       get {
+                               return _proposed;
+                       }
+                       set {
+                               if (Table != null) {
+                                       //Table.RecordCache[_proposed] = null;
+                                       Table.RecordCache[value] = this;
+                               }
+                               _proposed = value;
+                       }
+               }
+
+               #endregion
+
+               #region Methods
+
+               //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
+               //to a Datatable so I added this method. Delete if there is a better way.
+               internal void AttachRow() {
+                       if (Proposed != -1) {
+                               if (Current >= 0) {
+                                       Table.RecordCache.DisposeRecord(Current);
+                               }
+                               Current = Proposed;
+                               Proposed = -1;
+                       }
+               }
+
+               //FIXME?: Couldn't find a way to set the RowState when removing the DataRow
+               //from a Datatable so I added this method. Delete if there is a better way.
+               internal void DetachRow() {
+                       if (Proposed >= 0) {
+                               _table.RecordCache.DisposeRecord(Proposed);
+                               if (Proposed == Current) {
+                                       Current = -1;
+                               }
+                               if (Proposed == Original) {
+                                       Original = -1;
+                               }
+                               Proposed = -1;
+                       }
+
+                       if (Current >= 0) {
+                               _table.RecordCache.DisposeRecord(Current);
+                               if (Current == Original) {
+                                       Original = -1;
+                               }
+                               Current = -1;
+                       }
+
+                       if (Original >= 0) {
+                               _table.RecordCache.DisposeRecord(Original);
+                               Original = -1;
+                       }
+
+                       _rowId = -1;
+                       _hasParentCollection = false;
+               }
+
+               internal void ImportRecord(int record)
+               {
+                       if (HasVersion(DataRowVersion.Proposed)) {
+                               Table.RecordCache.DisposeRecord(Proposed);
+                       }
+
+                       Proposed = record;
+
+                       foreach(DataColumn column in Table.Columns.AutoIncrmentColumns) {
+                               column.UpdateAutoIncrementValue(column.DataContainer.GetInt64(Proposed));
+                       }
+
+               }
+
+               private void CheckValue (object v, DataColumn col) 
+               {               
+                       if (_hasParentCollection && col.ReadOnly) {
+                               throw new ReadOnlyException ();
+                       }
+
+                       if (v == null || v == DBNull.Value) {
+                               if (col.AllowDBNull || col.AutoIncrement || col.DefaultValue != DBNull.Value) {
+                                       return;
+                               }
+
+                               //Constraint violations during data load is raise in DataTable EndLoad
+                               this._nullConstraintViolation = true;
+                               if (this.Table._duringDataLoad) {
+                                       this.Table._nullConstraintViolationDuringDataLoad = true;
+                               }
+                               _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
+                       
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the custom error description for a row.
+               /// </summary>
+               public string RowError {
+                       get { 
+                               return rowError; 
+                       }
+                       set { 
+                               rowError = value; 
+                       }
+               }
+
+               internal int IndexFromVersion(DataRowVersion version)
+               {
+                       switch (version) {
+                               case DataRowVersion.Default:
+                                       if (Proposed >= 0)
+                                               return Proposed;
+
+                                       if (Current >= 0)
+                                               return Current;
+
+                                       if (Original < 0)
+                                               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.");
+
+                                       throw new DeletedRowInaccessibleException("Deleted row information cannot be accessed through the row.");
+
+                               case DataRowVersion.Proposed:
+                                       return AssertValidVersionIndex(version, Proposed);
+                               case DataRowVersion.Current:
+                                       return AssertValidVersionIndex(version, Current);
+                               case DataRowVersion.Original:
+                                       return AssertValidVersionIndex(version, Original);
+                               default:
+                                       throw new DataException ("Version must be Original, Current, or Proposed.");
+                       }
+               }
+
+               private int AssertValidVersionIndex(DataRowVersion version, int index) {
+                       if (index >= 0)
+                               return index;
+
+                       throw new VersionNotFoundException(String.Format("There is no {0} data to accces.", version));
+               }
+
+               internal DataRowVersion VersionFromIndex(int index) {
+                       if (index < 0)
+                               throw new ArgumentException("Index must not be negative.");
+
+                       // the order of ifs matters
+                       if (index == Current)
+                               return DataRowVersion.Current;
+                       if (index == Original)
+                               return DataRowVersion.Original;
+                       if (index == Proposed)
+                               return DataRowVersion.Proposed;
+
+                       throw new ArgumentException(String.Format("The index {0} does not belong to this row.", index)  );
+               }
+
+               internal XmlDataDocument.XmlDataElement DataElement {
+                       get { return mappedElement; }
+                       set { mappedElement = value; }
+               }
+
+               internal void SetOriginalValue (string columnName, object val)
+               {
+                       DataColumn column = _table.Columns[columnName];
+                       _table.ChangingDataColumn (this, column, val);
+                               
+                       if (Original < 0 || Original == Current) { 
+                               Original = Table.RecordCache.NewRecord();
+                       }
+                       CheckValue (val, column);
+                       column[Original] = val;
+               }
+
+               /// <summary>
+               /// Commits all the changes made to this row since the last time AcceptChanges was
+               /// called.
+               /// </summary>
+               public void AcceptChanges () 
+               {
+                       EndEdit(); // in case it hasn't been called
+
+                        _table.ChangingDataRow (this, DataRowAction.Commit);
+                       CheckChildRows(DataRowAction.Commit);
+                       switch (RowState) {
+                               case DataRowState.Unchanged:
+                                       return;
+                       case DataRowState.Added:
+                       case DataRowState.Modified:
+                                       if (Original >= 0) {
+                                               Table.RecordCache.DisposeRecord(Original);
+                                       }
+                                       Original = Current;
+                               break;
+                       case DataRowState.Deleted:
+                               _table.Rows.RemoveInternal (this);
+                               DetachRow();
+                               break;
+                       case DataRowState.Detached:
+                               throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
+                       }
+
+                        _table.ChangedDataRow (this, DataRowAction.Commit);
+               }
+
+               /// <summary>
+               /// Begins an edit operation on a DataRow object.
+               /// </summary>
+               public void BeginEdit () 
+               {
+                       if (_inChangingEvent)
+                                throw new InRowChangingEventException("Cannot call BeginEdit inside an OnRowChanging event.");
+                       if (RowState == DataRowState.Deleted)
+                               throw new DeletedRowInaccessibleException ();
+
+                       if (!HasVersion (DataRowVersion.Proposed)) {
+                               Proposed = Table.RecordCache.NewRecord();
+                               int from = HasVersion(DataRowVersion.Current) ? Current : Table.DefaultValuesRowIndex;
+                               for(int i = 0; i < Table.Columns.Count; i++){
+                                       DataColumn column = Table.Columns[i];
+                                       column.DataContainer.CopyValue(from,Proposed);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Cancels the current edit on the row.
+               /// </summary>
+               public void CancelEdit () 
+               {
+                        if (_inChangingEvent) {
+                                throw new InRowChangingEventException("Cannot call CancelEdit inside an OnRowChanging event.");
+                        }
+
+                       if (HasVersion (DataRowVersion.Proposed)) {
+                               Table.RecordCache.DisposeRecord(Proposed);
+                               Proposed = -1;
+                       }
+               }
+
+               /// <summary>
+               /// Clears the errors for the row, including the RowError and errors set with
+               /// SetColumnError.
+               /// </summary>
+               public void ClearErrors () 
+               {
+                       rowError = String.Empty;
+                       ColumnErrors.Clear();
+               }
+
+               /// <summary>
+               /// Deletes the DataRow.
+               /// </summary>
+               public void Delete () 
+               {
+                       _table.DeletingDataRow(this, DataRowAction.Delete);
+                       switch (RowState) {
+                       case DataRowState.Added:
+                               // check what to do with child rows
+                               CheckChildRows(DataRowAction.Delete);
+                               _table.DeleteRowFromIndexes (this);
+                               Table.Rows.RemoveInternal (this);
+
+                               // if row was in Added state we move it to Detached.
+                               DetachRow();
+                               break;
+                       case DataRowState.Deleted:
+                               break;          
+                       default:
+                               // check what to do with child rows
+                               CheckChildRows(DataRowAction.Delete);
+                               _table.DeleteRowFromIndexes (this);
+                               break;
+                       }
+                       if (Current >= 0) {
+                               if (Current != Original) {
+                                       _table.RecordCache.DisposeRecord(Current);
+                               }
+                               Current = -1;
+                       }
+                       _table.DeletedDataRow(this, DataRowAction.Delete);
+               }
+
+               // check the child rows of this row before deleting the row.
+               private void CheckChildRows(DataRowAction action)
+               {
+                       
+                       // in this method we find the row that this row is in a relation with them.
+                       // in shortly we find all child rows of this row.
+                       // then we function according to the DeleteRule of the foriegnkey.
+
+
+                       // 1. find if this row is attached to dataset.
+                       // 2. find if EnforceConstraints is true.
+                       // 3. find if there are any constraint on the table that the row is in.
+                       if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)
+                       {
+                               foreach (DataTable table in _table.DataSet.Tables)
+                               {
+                                       // loop on all ForeignKeyConstrain of the table.
+                                       foreach (Constraint constraint in table.Constraints) {
+                                               if (constraint is ForeignKeyConstraint) { 
+                                                       ForeignKeyConstraint fk = (ForeignKeyConstraint) constraint;
+                                                       if (fk.RelatedTable == _table) {
+                                                               switch (action) {
+                                                                       case DataRowAction.Delete:
+                                                                               CheckChildRows(fk, action, fk.DeleteRule);
+                                                                               break;
+                                                                       case DataRowAction.Commit:
+                                                                       case DataRowAction.Rollback:
+                                                                               if (fk.AcceptRejectRule != AcceptRejectRule.None)
+                                                                                       CheckChildRows(fk, action, Rule.Cascade);
+                                                                               break;
+                                                                       default:
+                                                                               CheckChildRows(fk, action, fk.UpdateRule);
+                                                                               break;
+                                                               }
+                                                       }                       
+                                               }                       
+                                       }
+                               }
+                       }
+               }
+
+               private void CheckChildRows(ForeignKeyConstraint fkc, DataRowAction action, Rule rule)
+               {                               
+                       DataRow[] childRows = GetChildRows(fkc, DataRowVersion.Current);
+                       switch (rule)
+                       {
+                               case Rule.Cascade:  // delete or change all relted rows.
+                                       if (childRows != null)
+                                       {
+                                               for (int j = 0; j < childRows.Length; j++)
+                                               {
+                                                       // if action is delete we delete all child rows
+                                                       switch(action) {
+                                                               case DataRowAction.Delete: {
+                                                               if (childRows[j].RowState != DataRowState.Deleted)
+                                                                       childRows[j].Delete();
+
+                                                                       break;
+                                                       }
+                                                       // if action is change we change the values in the child row
+                                                               case DataRowAction.Change: {
+                                                               // change only the values in the key columns
+                                                               // set the childcolumn value to the new parent row value
+                                                               for (int k = 0; k < fkc.Columns.Length; k++)
+                                                                       childRows[j][fkc.Columns[k]] = this[fkc.RelatedColumns[k], DataRowVersion.Proposed];
+
+                                                                       break;
+                                                               }
+
+                                                               case DataRowAction.Rollback: {
+                                                                       if (childRows[j].RowState != DataRowState.Unchanged)
+                                                                               childRows[j].RejectChanges ();
+
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       break;
+                               case Rule.None: // throw an exception if there are any child rows.
+                                       if (childRows != null)
+                                       {
+                                               for (int j = 0; j < childRows.Length; j++)
+                                               {
+                                                       if (childRows[j].RowState != DataRowState.Deleted)
+                                                       {
+                                                               string changeStr = "Cannot change this row because constraints are enforced on relation " + fkc.ConstraintName +", and changing this row will strand child rows.";
+                                                               string delStr = "Cannot delete this row because constraints are enforced on relation " + fkc.ConstraintName +", and deleting this row will strand child rows.";
+                                                               string message = action == DataRowAction.Delete ? delStr : changeStr;
+                                                               throw new InvalidConstraintException(message);
+                                                       }
+                                               }
+                                       }
+                                       break;
+                               case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.
+                                       if (childRows != null && childRows.Length > 0) {
+                                               int defaultValuesRowIndex = childRows[0].Table.DefaultValuesRowIndex;
+                                               foreach(DataRow childRow in childRows) {
+                                                       if (childRow.RowState != DataRowState.Deleted) {
+                                                               int defaultIdx = childRow.IndexFromVersion(DataRowVersion.Default);
+                                                               foreach(DataColumn column in fkc.Columns) {
+                                                                       column.DataContainer.CopyValue(defaultValuesRowIndex,defaultIdx);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       break;
+                               case Rule.SetNull: // set the values in the child row to null.
+                                       if (childRows != null)
+                                       {
+                                               for (int j = 0; j < childRows.Length; j++)
+                                               {
+                                                       DataRow child = childRows[j];
+                                                       if (childRows[j].RowState != DataRowState.Deleted)
+                                                       {
+                                                               // set only the key columns to DBNull
+                                                               for (int k = 0; k < fkc.Columns.Length; k++)
+                                                                       child.SetNull(fkc.Columns[k]);
+                                                       }
+                                               }
+                                       }
+                                       break;
+                       }
+
+               }
+
+               /// <summary>
+               /// Ends the edit occurring on the row.
+               /// </summary>
+               public void EndEdit () 
+               {
+                       if (_inChangingEvent)
+                               throw new InRowChangingEventException("Cannot call EndEdit inside an OnRowChanging event.");
+
+                       if (RowState == DataRowState.Detached)
+                               return;
+                       
+                       if (HasVersion (DataRowVersion.Proposed))
+                       {
+                               CheckReadOnlyStatus();
+
+                               _inChangingEvent = true;
+                               try
+                               {
+                                       _table.ChangingDataRow(this, DataRowAction.Change);
+                               }
+                               finally
+                               {
+                                       _inChangingEvent = false;
+                               }
+                               
+                               //Calling next method validates UniqueConstraints
+                               //and ForeignKeys.
+                               bool rowValidated = false;
+                               try
+                               {
+                                       if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad) {
+                                               _table.Rows.ValidateDataRowInternal(this);
+                                               rowValidated = true;
+                                       }
+                               }
+                               catch (Exception e)
+                               {
+                                       Table.RecordCache.DisposeRecord(Proposed);
+                                       Proposed = -1;
+                                       throw e;
+                               }
+
+                                       CheckChildRows(DataRowAction.Change);
+                               if (Original != Current) {
+                                       Table.RecordCache.DisposeRecord(Current);
+                               }
+
+                               Current = Proposed;
+                               Proposed = -1;
+
+                               if (!rowValidated) {
+                                       // keep indexes updated even if there was no need to validate row
+                                       foreach(Index index in Table.Indexes) {
+                                               index.Update(this,Current); //FIXME: why Current ?!
+                                       }
+                               }
+
+                               // Note : row state must not be changed before all the job on indexes finished,
+                               // since the indexes works with recods rather than with rows and the decision
+                               // which of row records to choose depends on row state.
+                               _table.ChangedDataRow(this, DataRowAction.Change);
+                       }
+               }
+
+               /// <summary>
+               /// Gets the child rows of this DataRow using the specified DataRelation.
+               /// </summary>
+               public DataRow[] GetChildRows (DataRelation relation) 
+               {
+                       return GetChildRows (relation, DataRowVersion.Default);
+               }
+
+               /// <summary>
+               /// Gets the child rows of a DataRow using the specified RelationName of a
+               /// DataRelation.
+               /// </summary>
+               public DataRow[] GetChildRows (string relationName) 
+               {
+                       return GetChildRows (Table.DataSet.Relations[relationName]);
+               }
+
+               /// <summary>
+               /// Gets the child rows of a DataRow using the specified DataRelation, and
+               /// DataRowVersion.
+               /// </summary>
+               public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version) 
+               {
+                       if (relation == null)
+                               return Table.NewRowArray(0);
+
+                       if (this.Table == null)
+                               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.");
+
+                       if (relation.DataSet != this.Table.DataSet)
+                               throw new ArgumentException();
+
+                       if (_table != relation.ParentTable)
+                               throw new InvalidConstraintException ("GetChildRow requires a row whose Table is " + relation.ParentTable + ", but the specified row's table is " + _table);
+
+                       if (relation.ChildKeyConstraint != null)
+                               return GetChildRows (relation.ChildKeyConstraint, version);
+
+                       ArrayList rows = new ArrayList();
+                       DataColumn[] parentColumns = relation.ParentColumns;
+                       DataColumn[] childColumns = relation.ChildColumns;
+                       int numColumn = parentColumns.Length;
+                       DataRow[] result = null;
+
+                       int versionIndex = IndexFromVersion(version);
+                       int tmpRecord = relation.ChildTable.RecordCache.NewRecord();
+
+                       try {
+                               for (int i = 0; i < numColumn; i++) {
+                                       // according to MSDN: the DataType value for both columns must be identical.
+                                       childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, versionIndex, tmpRecord);
+                               }
+
+                               Index index = relation.ChildTable.FindIndex(childColumns);
+
+                               if (index != null) {
+                                       int[] records = index.FindAll(tmpRecord);
+                                       result = relation.ChildTable.NewRowArray(records.Length);
+                                       for(int i=0; i < records.Length; i++) {
+                                               result[i] = relation.ChildTable.RecordCache[records[i]];
+                                       }
+                               }
+                               else {
+                                       foreach (DataRow row in relation.ChildTable.Rows) {
+                                               bool allColumnsMatch = false;
+                                               if (row.HasVersion(DataRowVersion.Default)) {
+                                                       allColumnsMatch = true;
+                                                       int childIndex = row.IndexFromVersion(DataRowVersion.Default);
+                                                       for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) {
+                                                               if (childColumns[columnCnt].DataContainer.CompareValues(childIndex, tmpRecord) != 0) {
+                                                               allColumnsMatch = false;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       if (allColumnsMatch) rows.Add(row);
+                               }
+                                       result = relation.ChildTable.NewRowArray(rows.Count);
+                                       rows.CopyTo(result, 0);
+                               }
+                       }
+                       finally {
+                               relation.ChildTable.RecordCache.DisposeRecord(tmpRecord);
+                       }                       
+
+                       return result;
+               }
+
+               /// <summary>
+               /// Gets the child rows of a DataRow using the specified RelationName of a
+               /// DataRelation, and DataRowVersion.
+               /// </summary>
+               public DataRow[] GetChildRows (string relationName, DataRowVersion version) 
+               {
+                       return GetChildRows (Table.DataSet.Relations[relationName], version);
+               }
+
+               private DataRow[] GetChildRows (ForeignKeyConstraint fkc, DataRowVersion version) 
+               {
+                       ArrayList rows = new ArrayList();
+                       DataColumn[] parentColumns = fkc.RelatedColumns;
+                       DataColumn[] childColumns = fkc.Columns;
+                       int numColumn = parentColumns.Length;
+
+                               Index index = fkc.Index;
+
+                       int curIndex = IndexFromVersion(version);
+                       int tmpRecord = fkc.Table.RecordCache.NewRecord();
+                       for (int i = 0; i < numColumn; i++) {
+                               // according to MSDN: the DataType value for both columns must be identical.
+                               childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, curIndex, tmpRecord);
+                       }
+
+                       try {
+                               if (index != null) {
+                                       // get the child rows from the index
+                                       int[] childRecords = index.FindAll(tmpRecord);
+                                       for (int i = 0; i < childRecords.Length; i++) {
+                                               rows.Add (childColumns[i].Table.RecordCache[childRecords[i]]);
+                                       }
+                               }
+                               else { // if there is no index we search manualy.
+                                               foreach (DataRow row in fkc.Table.Rows) {
+                                                       bool allColumnsMatch = false;
+                                                       if (row.HasVersion(DataRowVersion.Default)) {
+                                                               allColumnsMatch = true;
+                                                               int childIndex = row.IndexFromVersion(DataRowVersion.Default);
+                                                               for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) {
+                                                                       if (childColumns[columnCnt].DataContainer.CompareValues(childIndex, tmpRecord) != 0) {
+                                                                               allColumnsMatch = false;
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (allColumnsMatch) {
+                                                               rows.Add(row);
+                                                       }
+                                               }
+                                       }
+                       }
+                                       finally {
+                                               fkc.Table.RecordCache.DisposeRecord(tmpRecord);
+                                       }
+
+                       DataRow[] result = fkc.Table.NewRowArray(rows.Count);
+                       rows.CopyTo(result, 0);
+                       return result;
+               }
+
+               /// <summary>
+               /// Gets the error description of the specified DataColumn.
+               /// </summary>
+               public string GetColumnError (DataColumn column) 
+               {
+                       if (column == null)
+                               throw new ArgumentNullException("column");
+
+                       int index = _table.Columns.IndexOf(column);
+                       if (index < 0)
+                               throw new ArgumentException(String.Format("Column '{0}' does not belong to table {1}.", column.ColumnName, Table.TableName));
+
+                       return GetColumnError (index);
+               }
+
+               /// <summary>
+               /// Gets the error description for the column specified by index.
+               /// </summary>
+               public string GetColumnError (int columnIndex) 
+               {
+                       if (columnIndex < 0 || columnIndex >= Table.Columns.Count)
+                               throw new IndexOutOfRangeException ();
+
+                       string retVal = null;
+                       if (columnIndex < ColumnErrors.Count) {
+                               retVal = (String) ColumnErrors[columnIndex];
+                       }
+                       return (retVal != null) ? retVal : String.Empty;
+               }
+
+               /// <summary>
+               /// Gets the error description for the column, specified by name.
+               /// </summary>
+               public string GetColumnError (string columnName) 
+               {
+                       return GetColumnError (_table.Columns.IndexOf(columnName));
+               }
+
+               /// <summary>
+               /// Gets an array of columns that have errors.
+               /// </summary>
+               public DataColumn[] GetColumnsInError () 
+               {
+                       ArrayList dataColumns = new ArrayList ();
+
+                       int columnOrdinal = 0;
+                       foreach(String columnError in ColumnErrors) {
+                               if (columnError != null && columnError != String.Empty) {
+                                       dataColumns.Add (_table.Columns[columnOrdinal]);
+                               }
+                               columnOrdinal++;
+                       }
+
+                       return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));
+               }
+
+               /// <summary>
+               /// Gets the parent row of a DataRow using the specified DataRelation.
+               /// </summary>
+               public DataRow GetParentRow (DataRelation relation) 
+               {
+                       return GetParentRow (relation, DataRowVersion.Default);
+               }
+
+               /// <summary>
+               /// Gets the parent row of a DataRow using the specified RelationName of a
+               /// DataRelation.
+               /// </summary>
+               public DataRow GetParentRow (string relationName) 
+               {
+                       return GetParentRow (relationName, DataRowVersion.Default);
+               }
+
+               /// <summary>
+               /// Gets the parent row of a DataRow using the specified DataRelation, and
+               /// DataRowVersion.
+               /// </summary>
+               public DataRow GetParentRow (DataRelation relation, DataRowVersion version) 
+               {
+                       DataRow[] rows = GetParentRows(relation, version);
+                       if (rows.Length == 0) return null;
+                       return rows[0];
+               }
+
+               /// <summary>
+               /// Gets the parent row of a DataRow using the specified RelationName of a 
+               /// DataRelation, and DataRowVersion.
+               /// </summary>
+               public DataRow GetParentRow (string relationName, DataRowVersion version) 
+               {
+                       return GetParentRow (Table.DataSet.Relations[relationName], version);
+               }
+
+               /// <summary>
+               /// Gets the parent rows of a DataRow using the specified DataRelation.
+               /// </summary>
+               public DataRow[] GetParentRows (DataRelation relation) 
+               {
+                       return GetParentRows (relation, DataRowVersion.Default);
+               }
+
+               /// <summary>
+               /// Gets the parent rows of a DataRow using the specified RelationName of a 
+               /// DataRelation.
+               /// </summary>
+               public DataRow[] GetParentRows (string relationName) 
+               {
+                       return GetParentRows (relationName, DataRowVersion.Default);
+               }
+
+               /// <summary>
+               /// Gets the parent rows of a DataRow using the specified DataRelation, and
+               /// DataRowVersion.
+               /// </summary>
+               public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version) 
+               {
+                       // TODO: Caching for better preformance
+                       if (relation == null)
+                               return Table.NewRowArray(0);
+
+                       if (this.Table == null)
+                               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.");
+
+                       if (relation.DataSet != this.Table.DataSet)
+                               throw new ArgumentException();
+
+                       if (_table != relation.ChildTable)
+                               throw new InvalidConstraintException ("GetParentRows requires a row whose Table is " + relation.ChildTable + ", but the specified row's table is " + _table);
+
+                       ArrayList rows = new ArrayList();
+                       DataColumn[] parentColumns = relation.ParentColumns;
+                       DataColumn[] childColumns = relation.ChildColumns;
+                       int numColumn = parentColumns.Length;
+
+                       int curIndex = IndexFromVersion(version);
+                                       int tmpRecord = relation.ParentTable.RecordCache.NewRecord();
+                                               for (int i = 0; i < numColumn; i++) {
+                                                       // according to MSDN: the DataType value for both columns must be identical.
+                                                       parentColumns[i].DataContainer.CopyValue(childColumns[i].DataContainer, curIndex, tmpRecord);
+                                               }
+
+                       try {
+                               Index index = relation.ParentTable.FindIndex(parentColumns);
+                               if (index != null) { // get the parent rows from the index
+                                       int[] parentRecords = index.FindAll(tmpRecord);
+                                       for (int i = 0; i < parentRecords.Length; i++) {
+                                               rows.Add (parentColumns[i].Table.RecordCache[parentRecords[i]]);
+                                       }
+                               }
+                               else { // no index so we have to search manualy.
+                                               foreach (DataRow row in relation.ParentTable.Rows) {
+                                                       bool allColumnsMatch = false;
+                                                       if (row.HasVersion(DataRowVersion.Default)) {
+                                                               allColumnsMatch = true;
+                                                               int parentIndex = row.IndexFromVersion(DataRowVersion.Default);
+                                                               for (int columnCnt = 0; columnCnt < numColumn; columnCnt++) {
+                                                                       if (parentColumns[columnCnt].DataContainer.CompareValues(parentIndex, tmpRecord) != 0) {
+                                                                               allColumnsMatch = false;
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (allColumnsMatch) {
+                                                               rows.Add(row);
+                                                       }
+                                               }
+                                       }
+                       }
+                                       finally {
+                                               relation.ParentTable.RecordCache.DisposeRecord(tmpRecord);
+                                       }
+
+                       DataRow[] result = relation.ParentTable.NewRowArray(rows.Count);
+                       rows.CopyTo(result, 0);
+                       return result;
+               }
+
+               /// <summary>
+               /// Gets the parent rows of a DataRow using the specified RelationName of a 
+               /// DataRelation, and DataRowVersion.
+               /// </summary>
+               public DataRow[] GetParentRows (string relationName, DataRowVersion version) 
+               {
+                       return GetParentRows (Table.DataSet.Relations[relationName], version);
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether a specified version exists.
+               /// </summary>
+               public bool HasVersion (DataRowVersion version) 
+               {
+                       switch (version) {
+                               case DataRowVersion.Default:
+                                       return (Proposed >= 0 || Current >= 0);
+                               case DataRowVersion.Proposed:
+                                       return Proposed >= 0;
+                               case DataRowVersion.Current:
+                                       return Current >= 0;
+                               case DataRowVersion.Original:
+                                       return Original >= 0;
+                               default:
+                                       return IndexFromVersion(version) >= 0;
+                       }
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether the specified DataColumn contains a null value.
+               /// </summary>
+               public bool IsNull (DataColumn column) 
+               {
+                       return IsNull(column, DataRowVersion.Default);
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether the column at the specified index contains a null
+               /// value.
+               /// </summary>
+               public bool IsNull (int columnIndex) 
+               {
+                       return IsNull(Table.Columns[columnIndex]);
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether the named column contains a null value.
+               /// </summary>
+               public bool IsNull (string columnName) 
+               {
+                       return IsNull(Table.Columns[columnName]);
+               }
+
+               /// <summary>
+               /// Gets a value indicating whether the specified DataColumn and DataRowVersion
+               /// contains a null value.
+               /// </summary>
+               public bool IsNull (DataColumn column, DataRowVersion version) 
+               {
+                       object o = this[column,version];
+                       return column.DataContainer.IsNull(IndexFromVersion(version));
+               }
+
+               /// <summary>
+               /// Returns a value indicating whether all of the row columns specified contain a null value.
+               /// </summary>
+               internal bool IsNullColumns(DataColumn[] columns)
+               {
+                       bool allNull = true;
+                       for (int i = 0; i < columns.Length; i++) 
+                       {
+                               if (!IsNull(columns[i])) 
+                               {
+                                       allNull = false;
+                                       break;
+                               }
+                       }
+                       return allNull;
+               }
+
+               /// <summary>
+               /// Rejects all changes made to the row since AcceptChanges was last called.
+               /// </summary>
+               public void RejectChanges () 
+               {
+                       if (RowState == DataRowState.Detached)
+                               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.");
+                       // If original is null, then nothing has happened since AcceptChanges
+                       // was last called.  We have no "original" to go back to.
+                       if (HasVersion(DataRowVersion.Original)) {
+                               if (Current >= 0 && Current != Original) {
+                                       Table.RecordCache.DisposeRecord(Current);
+                               }
+                               CheckChildRows(DataRowAction.Rollback);
+
+                               Current = Original;
+                              
+                               _table.ChangedDataRow (this, DataRowAction.Rollback);
+                               CancelEdit ();
+                               switch (RowState)
+                               {
+                                       case DataRowState.Added:
+                                               _table.DeleteRowFromIndexes (this);
+                                               _table.Rows.RemoveInternal (this);
+                                               break;
+                                       case DataRowState.Modified:
+                                               if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
+                                                       _table.Rows.ValidateDataRowInternal(this);
+                                               break;
+                                       case DataRowState.Deleted:
+                                               if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
+                                                       _table.Rows.ValidateDataRowInternal(this);
+                                               break;
+                               } 
+                               
+                       }                       
+                       else {
+                               // If rows are just loaded via Xml the original values are null.
+                               // So in this case we have to remove all columns.
+                               // FIXME: I'm not realy sure, does this break something else, but
+                               // if so: FIXME ;)
+                               
+                               if ((RowState & DataRowState.Added) > 0)
+                               {
+                                       _table.DeleteRowFromIndexes (this);
+                                       _table.Rows.RemoveInternal (this);
+                                       // if row was in Added state we move it to Detached.
+                                       DetachRow();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Sets the error description for a column specified as a DataColumn.
+               /// </summary>
+               public void SetColumnError (DataColumn column, string error) 
+               {
+                       SetColumnError (_table.Columns.IndexOf (column), error);
+               }
+
+               /// <summary>
+               /// Sets the error description for a column specified by index.
+               /// </summary>
+               public void SetColumnError (int columnIndex, string error) 
+               {
+                       if (columnIndex < 0 || columnIndex >= Table.Columns.Count)
+                               throw new IndexOutOfRangeException ();
+
+                       while(ColumnErrors.Count < columnIndex) {
+                               ColumnErrors.Add(null);
+                       }
+                       ColumnErrors.Add(error);
+               }
+
+               /// <summary>
+               /// Sets the error description for a column specified by name.
+               /// </summary>
+               public void SetColumnError (string columnName, string error) 
+               {
+                       SetColumnError (_table.Columns.IndexOf (columnName), error);
+               }
+
+               /// <summary>
+               /// Sets the value of the specified DataColumn to a null value.
+               /// </summary>
+               protected void SetNull (DataColumn column) 
+               {
+                       this[column] = DBNull.Value;
+               }
+
+               /// <summary>
+               /// Sets the parent row of a DataRow with specified new parent DataRow.
+               /// </summary>
+               public void SetParentRow (DataRow parentRow) 
+               {
+                       SetParentRow(parentRow, null);
+               }
+
+               /// <summary>
+               /// Sets the parent row of a DataRow with specified new parent DataRow and
+               /// DataRelation.
+               /// </summary>
+               public void SetParentRow (DataRow parentRow, DataRelation relation) 
+               {
+                       if (_table == null || parentRow.Table == null)
+                               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.");
+
+                       if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
+                               throw new ArgumentException();
+                       
+                       BeginEdit();
+
+                       IEnumerable relations; 
+                       if (relation == null) {
+                               relations = _table.ParentRelations;
+                       }
+                       else {
+                               relations = new DataRelation[] { relation };
+                       }
+
+                       foreach (DataRelation rel in relations)
+                       {
+                               DataColumn[] childCols = rel.ChildColumns;
+                               DataColumn[] parentCols = rel.ParentColumns;
+                               
+                               for (int i = 0; i < parentCols.Length; i++)
+                               {
+                                       if (parentRow == null) {
+                                               childCols[i].DataContainer[Proposed] = DBNull.Value;
+                                       }
+                                       else {
+                                               int defaultIdx = parentRow.IndexFromVersion(DataRowVersion.Default);
+                                               childCols[i].DataContainer.CopyValue(parentCols[i].DataContainer,defaultIdx,Proposed);
+                                       }
+                               }
+                               
+                       }
+
+                       EndEdit();
+               }
+               
+               //Copy all values of this DataRow to the row parameter.
+               internal void CopyValuesToRow(DataRow row)
+               {
+                       if (row == null)
+                               throw new ArgumentNullException("row");
+                       if (row == this)
+                               throw new ArgumentException("'row' is the same as this object");
+
+                       foreach(DataColumn column in Table.Columns) {
+                               DataColumn targetColumn = row.Table.Columns[column.ColumnName];
+                               //if a column with the same name exists in both rows copy the values
+                               if(targetColumn != null) {
+                                       int index = targetColumn.Ordinal;
+                                       if (HasVersion(DataRowVersion.Original)) {
+                                               if (row.Original < 0) {
+                                                       row.Original = row.Table.RecordCache.NewRecord();
+                                               }
+                                               object val = column[Original];
+                                               row.CheckValue(val, targetColumn);
+                                               targetColumn[row.Original] = val;
+                                       }
+                                       else {
+                                               if (row.Original > 0) {
+                                                       row.Table.RecordCache.DisposeRecord(row.Original);
+                                                       row.Original = -1;
+                                               }
+                                       }
+
+                                       if (HasVersion(DataRowVersion.Current)) {
+                                               if (row.Current < 0) {
+                                                       row.Current = row.Table.RecordCache.NewRecord();
+                                               }
+                                               object val = column[Current];
+                                               row.CheckValue(val, targetColumn);
+                                               targetColumn[row.Current] = val;
+                                       }
+                                       else {
+                                               if (row.Current > 0) {
+                                                       row.Table.RecordCache.DisposeRecord(row.Current);
+                                                       row.Current = -1;
+                                               }
+                                       }
+
+                                       if (HasVersion(DataRowVersion.Proposed)) {
+                                               if (row.Proposed < 0) {
+                                                       row.Proposed = row.Table.RecordCache.NewRecord();
+                                               }
+                                               object val = column[row.Proposed];
+                                               row.CheckValue(val, targetColumn);
+                                               targetColumn[row.Proposed] = val;
+                                       }
+                                       else {
+                                               if (row.Proposed > 0) {
+                                                       row.Table.RecordCache.DisposeRecord(row.Proposed);
+                                                       row.Proposed = -1;
+                                               }
+                                       }
+                               }
+                       }
+                       if (HasErrors) {
+                               CopyErrors(row);
+                       }
+               }
+
+               internal void CopyErrors(DataRow row)
+               {
+                       row.RowError = RowError;
+                       DataColumn[] errorColumns = GetColumnsInError();
+                       foreach(DataColumn col in errorColumns) {
+                               DataColumn targetColumn = row.Table.Columns[col.ColumnName];
+                               row.SetColumnError(targetColumn,GetColumnError(col));
+                       }
+               }
+
+               internal bool IsRowChanged(DataRowState rowState) {
+                       if((RowState & rowState) != 0)
+                               return true;
+
+                       //we need to find if child rows of this row changed.
+                       //if yes - we should return true
+
+                       // if the rowState is deleted we should get the original version of the row
+                       // else - we should get the current version of the row.
+                       DataRowVersion version = (rowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current;
+                       int count = Table.ChildRelations.Count;
+                       for (int i = 0; i < count; i++){
+                               DataRelation rel = Table.ChildRelations[i];
+                               DataRow[] childRows = GetChildRows(rel, version);
+                               for (int j = 0; j < childRows.Length; j++){
+                                       if (childRows[j].IsRowChanged(rowState))
+                                               return true;
+                               }
+                       }
+
+                       return false;
+               }
+
+               internal bool HasParentCollection
+               {
+                       get
+                       {
+                               return _hasParentCollection;
+                       }
+                       set
+                       {
+                               _hasParentCollection = value;
+                       }
+               }
+
+               internal void CheckNullConstraints()
+               {
+                       if (_nullConstraintViolation) {
+                               if (HasVersion(DataRowVersion.Proposed)) {
+                                       foreach(DataColumn column in Table.Columns) {
+                                               if (IsNull(column) && !column.AllowDBNull) {
+                                                       throw new NoNullAllowedException(_nullConstraintMessage);
+                                       }
+                               }
+                               }
+                               _nullConstraintViolation = false;
+                       }
+               }
+               
+               internal void CheckReadOnlyStatus() {
+                               int defaultIdx = IndexFromVersion(DataRowVersion.Default); 
+                               foreach(DataColumn column in Table.Columns) {
+                               if ((column.DataContainer.CompareValues(defaultIdx,Proposed) != 0) && column.ReadOnly) {
+                                       throw new ReadOnlyException();
+                        }
+                }
+                       }                       
+       
+               #endregion // Methods
+
+#if NET_2_0
+                /// <summary>
+                ///    This method loads a given value into the existing row affecting versions,
+                ///    state based on the LoadOption.  The matrix of changes for this method are as
+                ///    mentioned in the DataTable.Load (IDataReader, LoadOption) method.
+                /// </summary>
+                [MonoTODO ("Raise necessary Events")]
+                internal void Load (object [] values, LoadOption loadOption, bool is_new)
+                {
+                        DataRowAction action = DataRowAction.Change;
+
+                        int temp = Table.RecordCache.NewRecord ();
+                        for (int i = 0 ; i < Table.Columns.Count; i++)
+                                SetValue (i, values [i], temp);
+
+                        if (is_new) { // new row
+                                if (editing || RowState == DataRowState.Detached)
+                                        Proposed = temp;
+                                else
+                                        Current = temp;
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.OverwriteChanges 
+                            || (loadOption == LoadOption.PreserveChanges
+                                && rowState == DataRowState.Unchanged)) {
+                                Original = temp;
+                                if (editing)
+                                        Proposed = temp;
+                                else
+                                        Current = temp;
+                                rowState = DataRowState.Unchanged;
+                                action = DataRowAction.ChangeCurrentAndOriginal;
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.PreserveChanges) {
+                                if (rowState != DataRowState.Deleted) {
+                                        Original = temp;
+                                        rowState = DataRowState.Modified;
+                                        action   = DataRowAction.ChangeOriginal;
+                                }
+                                return;
+                        }
+                                
+                        bool not_used = true;
+                        // Upsert
+                        if (rowState != DataRowState.Deleted) {
+                                int index = editing ? _proposed : _current;
+                                if (! RecordCache.CompareRecords (Table, index, temp)) {
+                                        if (editing)
+                                                Proposed = temp;
+                                        else
+                                                Current = temp;
+                                        not_used = false;
+                                        if (rowState == DataRowState.Unchanged)
+                                                rowState = DataRowState.Modified;
+                                }
+                        }
+                                
+                        if (not_used)
+                                Table.RecordCache.DisposeRecord (temp);
+                }
+#endif // NET_2_0
+       }
+}