DataRow.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Data / System / Data / DataRow.cs / 1 / DataRow.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data {
    using System; 
    using System.Collections;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Xml;
 
 
    /// 
    /// Represents a row of data in a . 
    /// 
#if WINFSInternalOnly
    internal
#else 
    public
#endif 
    class DataRow { 
        private readonly DataTable _table;
        private readonly DataColumnCollection _columns; 

        internal int  oldRecord = -1;
        internal int  newRecord = -1;
        internal int  tempRecord; 
        internal int  _rowID = -1;
 
        internal DataRowAction _action; 

        internal bool  inChangingEvent; 
        internal bool  inDeletingEvent;
        internal bool  inCascade;

        private DataColumn _lastChangedColumn; // last successfully changed column 
        private int _countColumnChange;        // number of columns changed during edit mode
 
        private DataError  error; 
        private object    _element;
 
        private int _rbTreeNodeId; // if row is not detached, Id used for computing index in rows collection

        private static int _objectTypeCount; // Bid counter
        internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        ///     
        ///       Initializes a new instance of the DataRow.
        ///     
        ///    
        ///       Constructs a row from the builder. Only for internal usage..
        ///    
        ///  
        protected internal DataRow (DataRowBuilder builder) {
            tempRecord = builder._record; 
            _table = builder._table; 
            _columns = _table.Columns;
        } 

        internal XmlBoundElement  Element {
            get {
                return (XmlBoundElement) _element; 
            }
            set { 
                _element = value; 
            }
        } 

        internal DataColumn LastChangedColumn {
            get { // last successfully changed column or if multiple columns changed: null
                if (_countColumnChange != 1) { 
                    return null;
                } 
                return _lastChangedColumn; 
            }
            set { 
                _countColumnChange++;
                _lastChangedColumn = value;
            }
        } 

        internal bool HasPropertyChanged { 
            get { return (0 < _countColumnChange); } 
        }
 
        internal int RBTreeNodeId {
            get {
                return _rbTreeNodeId;
            } 
            set {
                Bid.Trace(" %d#, value=%d\n", ObjectID, value); 
                _rbTreeNodeId = value; 
            }
        } 

        /// 
        ///    Gets or sets the custom error description for a row.
        ///  
        public string RowError {
            get { 
                return(error == null ? String.Empty :error.Text); 
            }
            set { 
                Bid.Trace(" %d#, value='%ls'\n", ObjectID, value);
                if (error == null) {
                    if (!Common.ADP.IsEmpty(value)) {
                        error = new DataError(value); 
                    }
                    RowErrorChanged(); 
                } 
                else if(error.Text != value) {
                    error.Text = value; 
                    RowErrorChanged();
                }
            }
        } 

        private void RowErrorChanged() { 
            // We don't know wich record was used by view index. try to use both. 
            if (oldRecord != -1)
                _table.RecordChanged(oldRecord); 
            if (newRecord != -1)
                _table.RecordChanged(newRecord);
        }
 
        internal int rowID {
            get { 
                return _rowID; 
            }
            set { 
                ResetLastChangedColumn();
                _rowID = value;
            }
        } 

        ///  
        ///    Gets the current state of the row in regards to its relationship to the table. 
        /// 
        public DataRowState RowState { 
            get {
                /*
                if (oldRecord == -1 && newRecord == -1)
                    state = DataRowState.Detached; // 2 
                else if (oldRecord == newRecord)
                    state = DataRowState.Unchanged; // 2 
                else if (oldRecord == -1) 
                    state = DataRowState.Added; // 4
                else if (newRecord == -1) 
                    state = DataRowState.Deleted; // 4
                else
                    state = DataRowState.Modified; // 4
                */ 
                if (oldRecord == newRecord) {
                    if (oldRecord == -1) { 
                        return DataRowState.Detached; // 2 
                    }
                    if (0 < _columns.ColumnsImplementingIChangeTrackingCount) { 
                        foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) {
                            object value = this[dc];
                            if ((DBNull.Value != value) && ((IChangeTracking)value).IsChanged) {
                                return DataRowState.Modified; // 3 + _columns.columnsImplementingIChangeTracking.Count 
                            }
                        } 
                    } 
                    return DataRowState.Unchanged; // 3
                } 
                else if (oldRecord == -1) {
                    return DataRowState.Added; // 2
                }
                else if (newRecord == -1) { 
                    return DataRowState.Deleted; // 3
                } 
                return DataRowState.Modified; // 3 

            } 
        }

        /// 
        /// Gets the  
        /// for which this row has a schema.
        ///  
        public DataTable Table { 
            get {
                return _table; 
            }
        }

        ///  
        ///    Gets or sets the data stored in the column specified by index.
        ///  
        public object this[int columnIndex] { 
            get {
                DataColumn column = _columns[columnIndex]; 
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, DataRowVersion.Default, column[record]);
                return column[record]; 
            }
            set { 
                DataColumn column = _columns[columnIndex]; 
                this[column] = value;
            } 
        }

        internal void CheckForLoops(DataRelation rel){
            // don't check for loops in the diffgram 
            // because there may be some holes in the rowCollection
            // and index creation may fail. The check will be done 
            // after all the loading is done _and_ we are sure there 
            // are no holes in the collection.
            if (_table.fInLoadDiffgram || (_table.DataSet != null && _table.DataSet.fInLoadDiffgram)) 
              return;
            int count = _table.Rows.Count, i = 0;
            // need to optimize this for count > 100
            DataRow parent = this.GetParentRow(rel); 
            while (parent != null) {
                if ((parent == this) || (i>count)) 
                    throw ExceptionBuilder.NestedCircular(_table.TableName); 
                i++;
                parent = parent.GetParentRow(rel); 
            }
        }

        internal int GetNestedParentCount() { 
            int count = 0;
            DataRelation[] nestedParentRelations = _table.NestedParentRelations; 
            foreach(DataRelation rel in nestedParentRelations) { 
                if (rel == null) // don't like this but done for backward code compatability
                    continue; 
                if (rel.ParentTable == _table) // self-nested table
                    this.CheckForLoops(rel);
                DataRow row = this.GetParentRow(rel);
                if (row != null) { 
                    count++;
                } 
            } 
            return count ;
            // Rule 1: At all times, only ONE FK  "(in a row) can be non-Null 
            // we wont allow a row to have multiple parents, as we cant handle it , also in diffgram
        }

        ///  
        ///    Gets or sets the data stored in the column specified by
        ///       name. 
        ///  
        public object this[string columnName] {
            get { 
                DataColumn column = GetDataColumn(columnName);
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, DataRowVersion.Default, column[record]); 
                return column[record];
            } 
            set { 
                DataColumn column = GetDataColumn(columnName);
                this[column] = value; 
            }
        }

        ///  
        ///    Gets or sets
        ///       the data stored in the specified . 
        ///  
        public object this[DataColumn column] {
            get { 
                CheckColumn(column);
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, DataRowVersion.Default, column[record]); 
                return column[record];
            } 
            set { 
                CheckColumn(column);
                if (inChangingEvent) { 
                    throw ExceptionBuilder.EditInRowChanging();
                }
                if ((-1 != rowID) && column.ReadOnly) {
                    throw ExceptionBuilder.ReadOnly(column.ColumnName); 
                }
 
                // allow users to tailor the proposed value, or throw an exception. 
                // note we intentionally do not try/catch this event.
                // note: we also allow user to do anything at this point 
                // infinite loops are possible if user calls Item or ItemArray during the event
                DataColumnChangeEventArgs e = null;
                if (_table.NeedColumnChangeEvents) {
                    e = new DataColumnChangeEventArgs(this, column, value); 
                    _table.OnColumnChanging(e);
                } 
 
                if (column.Table != _table) {
                    // user removed column from table during OnColumnChanging event 
                    throw ExceptionBuilder.ColumnNotInTheTable(column.ColumnName, _table.TableName);
                }
                if ((-1 != rowID) && column.ReadOnly) {
                    // user adds row to table during OnColumnChanging event 
                    throw ExceptionBuilder.ReadOnly(column.ColumnName);
                } 
 
                object proposed = ((null != e) ? e.ProposedValue : value);
                if (null == proposed) { 
                    if (column.IsValueType) { // WebData 105963
                        throw ExceptionBuilder.CannotSetToNull(column);
                    }
                    proposed = DBNull.Value; 
                }
 
                bool immediate = BeginEditInternal(); 
                try {
                    int record = GetProposedRecordNo(); 
                    _table.recordManager.VerifyRecord(record, this);
                    column[record] = proposed;
                }
                catch (Exception e1){ 
                    //
                    if (Common.ADP.IsCatchableOrSecurityExceptionType(e1)) { 
                        if (immediate) { 
                            Debug.Assert(!inChangingEvent, "how are we in a changing event to cancel?");
                            Debug.Assert(-1 != tempRecord, "how no propsed record to cancel?"); 
                            CancelEdit(); // WebData 107154
                        }
                    }
                    throw; 
                }
                LastChangedColumn = column; 
 
                // note: we intentionally do not try/catch this event.
                // infinite loops are possible if user calls Item or ItemArray during the event 
                if (null != e) {
                    _table.OnColumnChanged(e); // user may call CancelEdit or EndEdit
                }
 
                if (immediate) {
                    Debug.Assert(!inChangingEvent, "how are we in a changing event to end?"); 
                    EndEdit(); 
                }
            } 
        }

        /// 
        ///    Gets the data stored 
        ///       in the column, specified by index and version of the data to retrieve.
        ///  
        public object this[int columnIndex, DataRowVersion version] { 
            get {
                DataColumn column = _columns[columnIndex]; 
                int record = GetRecordFromVersion(version);
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, version, column[record]);
                return column[record]; 
            }
        } 
 
        /// 
        ///     Gets the specified version of data stored in 
        ///       the named column.
        /// 
        public object this[string columnName, DataRowVersion version] {
            get { 
                DataColumn column = GetDataColumn(columnName);
                int record = GetRecordFromVersion(version); 
                _table.recordManager.VerifyRecord(record, this); 
                VerifyValueFromStorage(column, version, column[record]);
                return column[record]; 
            }
        }

        ///  
        /// Gets the specified version of data stored in the specified .
        ///  
        public object this[DataColumn column, DataRowVersion version] { 
            get {
                CheckColumn(column); 
                int record = GetRecordFromVersion(version);
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, version, column[record]);
                return column[record]; 
            }
        } 
 
        /// 
        ///    Gets 
        ///       or sets all of the values for this row through an array.
        /// 
        public object[] ItemArray {
            get { 
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this); 
                object[] values = new object[_columns.Count]; 
                for (int i = 0; i < values.Length; i++) {
                    DataColumn column = _columns[i]; 
                    VerifyValueFromStorage(column, DataRowVersion.Default, column[record]);
                    values[i] = column[record];
                }
                return values; 
            }
            set { 
                if (null == value) { // WebData 104372 
                    throw ExceptionBuilder.ArgumentNull("ItemArray");
                } 
                if (_columns.Count < value.Length) {
                    throw ExceptionBuilder.ValueArrayLength();
                }
                DataColumnChangeEventArgs e = null; 
                if (_table.NeedColumnChangeEvents) {
                    e = new DataColumnChangeEventArgs(this); 
                } 
                bool immediate = BeginEditInternal();
 
                for (int i = 0; i < value.Length; ++i) {
                    // Empty means don't change the row.
                    if (null != value[i]) {
                        // may throw exception if user removes column from table during event 
                        DataColumn column = _columns[i];
 
                        if ((-1 != rowID) && column.ReadOnly) { 
                            throw ExceptionBuilder.ReadOnly(column.ColumnName);
                        } 

                        // allow users to tailor the proposed value, or throw an exception.
                        // note: we intentionally do not try/catch this event.
                        // note: we also allow user to do anything at this point 
                        // infinite loops are possible if user calls Item or ItemArray during the event
                        if (null != e) { 
                            e.InitializeColumnChangeEvent(column, value[i]); 
                            _table.OnColumnChanging(e);
                        } 

                        if (column.Table != _table) {
                            // user removed column from table during OnColumnChanging event
                            throw ExceptionBuilder.ColumnNotInTheTable(column.ColumnName, _table.TableName); 
                        }
                        if ((-1 != rowID) && column.ReadOnly) { 
                            // user adds row to table during OnColumnChanging event 
                            throw ExceptionBuilder.ReadOnly(column.ColumnName);
                        } 
                        if (tempRecord == -1) {
                            // user affected CancelEdit or EndEdit during OnColumnChanging event of the last value
                            BeginEditInternal();
                        } 

                        object proposed = (null != e) ? e.ProposedValue : value[i]; 
                        if (null == proposed) { 
                            if (column.IsValueType) { // WebData 105963
                                throw ExceptionBuilder.CannotSetToNull(column); 
                            }
                            proposed = DBNull.Value;
                        }
 
                        try {
                            // must get proposed record after each event because user may have 
                            // called EndEdit(), AcceptChanges(), BeginEdit() during the event 
                            int record = GetProposedRecordNo();
                            _table.recordManager.VerifyRecord(record, this); 
                            column[record] = proposed;
                        }
                        catch (Exception e1) {
                            // 
                            if (Common.ADP.IsCatchableOrSecurityExceptionType(e1)) {
                                if (immediate) { 
                                    Debug.Assert(!inChangingEvent, "how are we in a changing event to cancel?"); 
                                    Debug.Assert(-1 != tempRecord, "how no propsed record to cancel?");
                                    CancelEdit(); // WebData 107154 
                                }
                            }
                            throw;
                        } 
                        LastChangedColumn = column;
 
                        // note: we intentionally do not try/catch this event. 
                        // infinite loops are possible if user calls Item or ItemArray during the event
                        if (null != e) { 
                            _table.OnColumnChanged(e);  // user may call CancelEdit or EndEdit
                        }
                    }
                } 

                // proposed breaking change: if (immediate){ EndEdit(); } because table currently always fires RowChangedEvent 
                Debug.Assert(!inChangingEvent, "how are we in a changing event to end?"); 
                EndEdit();
            } 
        }

        /// 
        ///    Commits all the changes made to this row 
        ///       since the last time  was called.
        ///  
        public void AcceptChanges() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                EndEdit();

                if (this.RowState != DataRowState.Detached && this.RowState != DataRowState.Deleted) { 
                    if (_columns.ColumnsImplementingIChangeTrackingCount > 0) {
                        foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) { 
                            object value = this[dc]; 
                            if (DBNull.Value != value) {
                                IChangeTracking tracking = (IChangeTracking)value; 
                                if (tracking.IsChanged) {
                                    tracking.AcceptChanges();
                                }
                            } 
                        }
                    } 
                } 
                _table.CommitRow(this);
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        ///  
        /// Begins an edit operation on a object. 
        /// 
        [ 
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ]
        public void BeginEdit() {
            BeginEditInternal(); 
        }
 
        private bool BeginEditInternal() { 
            if (inChangingEvent) {
                throw ExceptionBuilder.BeginEditInRowChanging(); 
            }
            if (tempRecord != -1) {
                if (tempRecord < _table.recordManager.LastFreeRecord) {
                    return false; // we will not call EndEdit 
                }
                else { 
                    // partial fix for detached row after Table.Clear scenario 
                    // in debug, it will have asserted earlier, but with this
                    // it will go get a new record for editing 
                    tempRecord = -1;
                }
                // shifted VerifyRecord to first make the correction, then verify
                _table.recordManager.VerifyRecord(tempRecord, this); 
            }
 
            if (oldRecord != -1 && newRecord == -1) { 
                throw ExceptionBuilder.DeletedRowInaccessible();
            } 

            //

            ResetLastChangedColumn(); // shouldn't have to do this 

            tempRecord = _table.NewRecord(newRecord); 
            Debug.Assert(-1 != tempRecord, "missing temp record"); 
            Debug.Assert(0 == _countColumnChange, "unexpected column change count");
            Debug.Assert(null == _lastChangedColumn, "unexpected last column change"); 
            return true;
        }

        ///  
        ///    Cancels the current edit on the row.
        ///  
        [ 
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ] 
        public void CancelEdit() {
            if (inChangingEvent) {
                throw ExceptionBuilder.CancelEditInRowChanging();
            } 

            _table.FreeRecord(ref tempRecord); 
            Debug.Assert(-1 == tempRecord, "unexpected temp record"); 
            ResetLastChangedColumn();
        } 

        private void CheckColumn(DataColumn column) {
            if (column == null) {
                throw ExceptionBuilder.ArgumentNull("column"); 
            }
 
            if (column.Table != _table) { 
                throw ExceptionBuilder.ColumnNotInTheTable(column.ColumnName, _table.TableName);
            } 
        }

        /// 
        /// Throws a RowNotInTableException if row isn't in table. 
        /// 
        internal void CheckInTable() { 
            if (rowID == -1) { 
                throw ExceptionBuilder.RowNotInTheTable();
            } 
        }

        /// 
        ///    Deletes the row. 
        /// 
        public void Delete() { 
            if (inDeletingEvent) { 
                throw ExceptionBuilder.DeleteInRowDeleting();
            } 

            if (newRecord == -1)
                return;
 
            _table.DeleteRow(this);
        } 
 
        /// 
        ///    Ends the edit occurring on the row. 
        /// 
        [
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ] 
        public void EndEdit() {
            if (inChangingEvent) { 
                throw ExceptionBuilder.EndEditInRowChanging(); 
            }
 
            if (newRecord == -1) {
                return; // this is meaningless, detatched row case
            }
 
            if (tempRecord != -1) {
                //int record = tempRecord; 
                //tempRecord = -1; 
                try {
                    SetNewRecord(tempRecord); 
                }
                finally {
                    // a constraint violation may be thrown during SetNewRecord
                    ResetLastChangedColumn(); 
                }
            } 
        } 

        ///  
        ///    Sets the error description for a column specified by index.
        /// 
        public void SetColumnError(int columnIndex, string error) {
            DataColumn column = _columns[columnIndex]; 
            if (column == null)
                throw ExceptionBuilder.ColumnOutOfRange(columnIndex); 
 
            SetColumnError(column, error);
        } 

        /// 
        ///    Sets
        ///       the error description for a column specified by name. 
        /// 
        public void SetColumnError(string columnName, string error) { 
            DataColumn column = GetDataColumn(columnName); 
            SetColumnError(column, error);
        } 

        /// 
        /// Sets the error description for a column specified as a .
        ///  
        public void SetColumnError(DataColumn column, string error) {
            CheckColumn(column); 
 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, column=%d, error='%ls'\n", ObjectID, column.ObjectID, error); 
            try {
                if (this.error == null)  this.error = new DataError();
                if(GetColumnError(column) != error) {
                    this.error.SetColumnError(column, error); 
                    RowErrorChanged();
                } 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        ///    Gets the error description for the column specified
        ///       by index. 
        ///  
        public string GetColumnError(int columnIndex) {
            DataColumn column = _columns[columnIndex]; 
            return GetColumnError(column);
        }

        ///  
        ///    Gets the error description for a column, specified by name.
        ///  
        public string GetColumnError(string columnName) { 
            DataColumn column = GetDataColumn(columnName);
            return GetColumnError(column); 
        }

        /// 
        ///    Gets the error description of 
        ///       the specified .
        ///  
        public string GetColumnError(DataColumn column) { 
            CheckColumn(column);
            if (error == null)  error = new DataError(); 
            return error.GetColumnError(column);
        }

        ///  
        /// Clears the errors for the row, including the 
        /// and errors set with  
        ///  
        public void ClearErrors() {
            if (error != null) { 
                error.Clear();
                RowErrorChanged();
            }
        } 

        internal void ClearError(DataColumn column) { 
            if (error != null) { 
                error.Clear(column);
                RowErrorChanged(); 
            }
        }

        ///  
        ///    Gets a value indicating whether there are errors in a columns collection.
        ///  
        public bool HasErrors { 
            get {
                return(error == null ? false : error.HasErrors); 
            }
        }

        ///  
        ///    Gets an array of columns that have errors.
        ///  
        public DataColumn[] GetColumnsInError() { 
            if (error == null)
                return DataTable.zeroColumns; 
            else
                return error.GetColumnsInError();
        }
 

        public DataRow[] GetChildRows(string relationName) { 
            return GetChildRows(_table.ChildRelations[relationName], DataRowVersion.Default); 
        }
 
        public DataRow[] GetChildRows(string relationName, DataRowVersion version) {
            return GetChildRows(_table.ChildRelations[relationName], version);
        }
 
        /// 
        /// Gets the child rows of this  using the 
        ///    specified  
        ///    .
        ///  
        public DataRow[] GetChildRows(DataRelation relation) {
            return GetChildRows(relation, DataRowVersion.Default);
        }
 
        /// 
        /// Gets the child rows of this  using the specified  and the specified  
        ///  
        public DataRow[] GetChildRows(DataRelation relation, DataRowVersion version) {
            if (relation == null) 
                return _table.NewRowArray(0);

            //if (-1 == rowID)
            //    throw ExceptionBuilder.RowNotInTheTable(); 

            if (relation.DataSet != _table.DataSet) 
                throw ExceptionBuilder.RowNotInTheDataSet(); 
            if (relation.ParentKey.Table != _table)
                throw ExceptionBuilder.RelationForeignTable(relation.ParentTable.TableName, _table.TableName); 
            return DataRelation.GetChildRows(relation.ParentKey, relation.ChildKey, this, version);
        }

        internal DataColumn GetDataColumn(string columnName) { 
            DataColumn column = _columns[columnName];
            if (null != column) { 
                return column; 
            }
            throw ExceptionBuilder.ColumnNotInTheTable(columnName, _table.TableName); 
        }

        public DataRow GetParentRow(string relationName) {
            return GetParentRow(_table.ParentRelations[relationName], DataRowVersion.Default); 
        }
 
        public DataRow GetParentRow(string relationName, DataRowVersion version) { 
            return GetParentRow(_table.ParentRelations[relationName], version);
        } 

        /// 
        /// Gets the parent row of this  using the specified  .
        ///  
        public DataRow GetParentRow(DataRelation relation) {
            return GetParentRow(relation, DataRowVersion.Default); 
        } 

        ///  
        /// Gets the parent row of this 
        /// using the specified  and .
        /// 
        public DataRow GetParentRow(DataRelation relation, DataRowVersion version) { 
            if (relation == null)
                return null; 
 
            //if (-1 == rowID)
            //    throw ExceptionBuilder.RowNotInTheTable(); 

            if (relation.DataSet != _table.DataSet)
                throw ExceptionBuilder.RelationForeignRow();
 
            if (relation.ChildKey.Table != _table)
                throw ExceptionBuilder.GetParentRowTableMismatch(relation.ChildTable.TableName, _table.TableName); 
 
            return DataRelation.GetParentRow(relation.ParentKey, relation.ChildKey, this, version);
        } 
        // a multiple nested child table's row can have only one non-null FK per row. So table has multiple
        // parents, but a row can have only one parent. Same nested row cannot below to 2 parent rows.
        internal DataRow GetNestedParentRow(DataRowVersion version) {
            // 1) Walk over all FKs and get the non-null. 2) Get the relation. 3) Get the parent Row. 
            DataRelation[] nestedParentRelations = _table.NestedParentRelations;
            foreach(DataRelation rel in nestedParentRelations) { 
                if (rel == null) // don't like this but done for backward code compatability 
                    continue;
                if (rel.ParentTable == _table) // self-nested table 
                    this.CheckForLoops(rel);
                DataRow row = this.GetParentRow(rel, version);
                if (row != null) {
                    return row; 
                }
            } 
            return null;// Rule 1: At all times, only ONE FK  "(in a row) can be non-Null 

        } 
        // No Nested in 1-many

        /// 
        ///    [To be supplied.] 
        /// 
        public DataRow[] GetParentRows(string relationName) { 
            return GetParentRows(_table.ParentRelations[relationName], DataRowVersion.Default); 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        public DataRow[] GetParentRows(string relationName, DataRowVersion version) { 
            return GetParentRows(_table.ParentRelations[relationName], version);
        } 
 
        /// 
        ///     
        ///       Gets the parent rows of this  using the specified  .
        ///    
        /// 
        public DataRow[] GetParentRows(DataRelation relation) { 
            return GetParentRows(relation, DataRowVersion.Default);
        } 
 
        /// 
        ///     
        ///       Gets the parent rows of this  using the specified  .
        ///    
        /// 
        public DataRow[] GetParentRows(DataRelation relation, DataRowVersion version) { 
            if (relation == null)
                return _table.NewRowArray(0); 
 
            //if (-1 == rowID)
            //    throw ExceptionBuilder.RowNotInTheTable(); 

            if (relation.DataSet != _table.DataSet)
                throw ExceptionBuilder.RowNotInTheDataSet();
 
            if (relation.ChildKey.Table != _table)
                throw ExceptionBuilder.GetParentRowTableMismatch(relation.ChildTable.TableName, _table.TableName); 
 
            return DataRelation.GetParentRows(relation.ParentKey, relation.ChildKey, this, version);
        } 

        internal object[] GetColumnValues(DataColumn[] columns) {
            return GetColumnValues(columns, DataRowVersion.Default);
        } 

        internal object[] GetColumnValues(DataColumn[] columns, DataRowVersion version) { 
            DataKey key = new DataKey(columns, false); // temporary key, don't copy columns 
            return GetKeyValues(key, version);
        } 

        internal object[] GetKeyValues(DataKey key) {
            int record = GetDefaultRecord();
            return key.GetKeyValues(record); 
        }
 
        internal object[] GetKeyValues(DataKey key, DataRowVersion version) { 
            int record = GetRecordFromVersion(version);
            return key.GetKeyValues(record); 
        }

        internal int GetCurrentRecordNo() {
            if (newRecord == -1) 
                throw ExceptionBuilder.NoCurrentData();
            return newRecord; 
        } 

        internal int GetDefaultRecord() { 
            if (tempRecord != -1)
                return tempRecord;
            if (newRecord != -1) {
                return newRecord; 
            }
            // If row has oldRecord - this is deleted row. 
            if (oldRecord == -1) 
                throw ExceptionBuilder.RowRemovedFromTheTable();
            else 
                throw ExceptionBuilder.DeletedRowInaccessible();
        }

        internal int GetOriginalRecordNo() { 
            if (oldRecord == -1)
                throw ExceptionBuilder.NoOriginalData(); 
            return oldRecord; 
        }
 
        private int GetProposedRecordNo() {
            if (tempRecord == -1)
                throw ExceptionBuilder.NoProposedData();
            return tempRecord; 
        }
 
        internal int GetRecordFromVersion(DataRowVersion version) { 
            switch (version) {
                case DataRowVersion.Original: 
                    return GetOriginalRecordNo();
                case DataRowVersion.Current:
                    return GetCurrentRecordNo();
                case DataRowVersion.Proposed: 
                    return GetProposedRecordNo();
                case DataRowVersion.Default: 
                    return GetDefaultRecord(); 
                default:
                    throw ExceptionBuilder.InvalidRowVersion(); 
            }
        }

        internal DataRowVersion GetDefaultRowVersion(DataViewRowState viewState) { 
            if (oldRecord == newRecord) {
                if (oldRecord == -1) { 
                    // should be DataView.addNewRow 
                    return DataRowVersion.Default;
                } 
                Debug.Assert(0 != (DataViewRowState.Unchanged & viewState), "not DataViewRowState.Unchanged");
                return DataRowVersion.Default;
            }
            else if (oldRecord == -1) { 
                Debug.Assert(0 != (DataViewRowState.Added & viewState), "not DataViewRowState.Added");
                return DataRowVersion.Default; 
            } 
            else if (newRecord == -1) {
                Debug.Assert(0 != (DataViewRowState.Deleted & viewState), "not DataViewRowState.Deleted"); 
                return DataRowVersion.Original;
            }
            else if (0 != (DataViewRowState.ModifiedCurrent & viewState)) {
                return DataRowVersion.Default; 
            }
            Debug.Assert(0 != (DataViewRowState.ModifiedOriginal & viewState), "not DataViewRowState.ModifiedOriginal"); 
            return DataRowVersion.Original; 
        }
 
        internal DataViewRowState GetRecordState(int record) {
            if (record == -1)
                return DataViewRowState.None;
            if (record == oldRecord && record == newRecord) 
                return DataViewRowState.Unchanged;
            if (record == oldRecord) 
                return(newRecord != -1) ? DataViewRowState.ModifiedOriginal : DataViewRowState.Deleted; 
            if (record == newRecord)
                return(oldRecord != -1) ? DataViewRowState.ModifiedCurrent : DataViewRowState.Added; 
            return DataViewRowState.None;
        }

        internal bool HasKeyChanged(DataKey key) { 
            return HasKeyChanged(key, DataRowVersion.Current, DataRowVersion.Proposed);
        } 
 
        internal bool HasKeyChanged(DataKey key, DataRowVersion version1, DataRowVersion version2) {
            if (!HasVersion(version1) || !HasVersion(version2)) 
                return true;
            return !key.RecordsEqual(GetRecordFromVersion(version1), GetRecordFromVersion(version2));
        }
 
        /// 
        ///     
        ///       Gets a value indicating whether a specified version exists. 
        ///    
        ///  
        public bool HasVersion(DataRowVersion version) {
            switch (version) {
                case DataRowVersion.Original:
                    return(oldRecord != -1); 
                case DataRowVersion.Current:
                    return(newRecord != -1); 
                case DataRowVersion.Proposed: 
                    return(tempRecord != -1);
                case DataRowVersion.Default: 
                    return(tempRecord != -1 || newRecord != -1);
                default:
                    throw ExceptionBuilder.InvalidRowVersion();
            } 
        }
 
        internal bool HasChanges() { 
            if (!HasVersion(DataRowVersion.Original) || !HasVersion(DataRowVersion.Current)) {
                return true; // if does not have original, its added row, if does not have current, its deleted row so it has changes 
            }
            foreach(DataColumn dc in Table.Columns) {
                if (dc.Compare(oldRecord, newRecord) != 0) {
                    return true; 
                }
            } 
            return false; 
        }
 
        internal bool HaveValuesChanged(DataColumn[] columns) {
            return HaveValuesChanged(columns, DataRowVersion.Current, DataRowVersion.Proposed);
        }
 
        internal bool HaveValuesChanged(DataColumn[] columns, DataRowVersion version1, DataRowVersion version2) {
            for (int i = 0; i < columns.Length; i++) { 
                CheckColumn(columns[i]); 
            }
            DataKey key = new DataKey(columns, false); // temporary key, don't copy columns 
            return HasKeyChanged(key, version1, version2);
        }

        ///  
        ///    
        ///       Gets 
        ///       a value indicating whether the column at the specified index contains a 
        ///       null value.
        ///     
        /// 
        public bool IsNull(int columnIndex) {
            DataColumn column = _columns[columnIndex];
            int record = GetDefaultRecord(); 
            return column.IsNull(record);
        } 
 
        /// 
        ///     
        ///       Gets a value indicating whether the named column contains a null value.
        ///    
        /// 
        public bool IsNull(string columnName) { 
            DataColumn column = GetDataColumn(columnName);
            int record = GetDefaultRecord(); 
            return column.IsNull(record); 
        }
 
        /// 
        ///    
        ///       Gets a value indicating whether the specified 
        ///       contains a null value. 
        ///    
        ///  
        public bool IsNull(DataColumn column) { 
            CheckColumn(column);
            int record = GetDefaultRecord(); 
            return column.IsNull(record);
        }

        ///  
        ///    [To be supplied.]
        ///  
        public bool IsNull(DataColumn column, DataRowVersion version) { 
            CheckColumn(column);
            int record = GetRecordFromVersion(version); 
            return column.IsNull(record);
        }

        ///  
        ///    
        ///       Rejects all changes made to the row since  
        ///       was last called. 
        ///    
        ///  
        public void RejectChanges() {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try { 
                if (this.RowState != DataRowState.Detached) {
                    if (_columns.ColumnsImplementingIChangeTrackingCount != _columns.ColumnsImplementingIRevertibleChangeTrackingCount) { 
                        foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) { 
                            if (!dc.ImplementsIRevertibleChangeTracking) {
                                object value = null; 
                                if (this.RowState != DataRowState.Deleted)
                                    value = this[dc];
                                else
                                    value = this[dc, DataRowVersion.Original]; 
                                if (DBNull.Value != value){
                                    if (((IChangeTracking)value).IsChanged) { 
                                        throw ExceptionBuilder.UDTImplementsIChangeTrackingButnotIRevertible(dc.DataType.AssemblyQualifiedName); 
                                    }
                                } 
                            }
                        }
                    }
                    foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) { 
                        object value = null;
                         if (this.RowState != DataRowState.Deleted) 
                            value = this[dc]; 
                         else
                            value = this[dc, DataRowVersion.Original]; 
                        if (DBNull.Value != value) {
                            IChangeTracking tracking = (IChangeTracking)value;
                            if (tracking.IsChanged) {
                                ((IRevertibleChangeTracking)value).RejectChanges(); 
                            }
                        } 
                    } 
                }
                _table.RollbackRow(this); 
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
        internal void ResetLastChangedColumn() { 
            _lastChangedColumn = null;
            _countColumnChange = 0; 
        }

        internal void SetKeyValues(DataKey key, object[] keyValues) {
            bool fFirstCall = true; 
            bool immediate = (tempRecord == -1);
 
            for (int i = 0; i < keyValues.Length; i++) { 
                object value = this[key.ColumnsReference[i]];
                if (!value.Equals(keyValues[i])) { 
                    if (immediate && fFirstCall) {
                        fFirstCall = false;
                        BeginEditInternal();
                    } 
                    this[key.ColumnsReference[i]] = keyValues[i];
                } 
            } 
            if (!fFirstCall)
                EndEdit(); 
        }

        // if it's a detached row, we can't add it, we'll just keep it as temp.
        internal void SetNewRecord(int record) { 
            //Debug.Assert(oldRecord != -1 || newRecord != -1, "You can't call SetNewRecord on a detached row.");
            _table.SetNewRecord(this, record, DataRowAction.Change, false, true); 
        } 

        ///  
        ///    
        ///       Sets the specified column's value to a null value.
        ///    
        ///  
        protected void SetNull(DataColumn column) {
            this[column] = DBNull.Value; 
        } 

        internal void SetNestedParentRow(DataRow parentRow, bool setNonNested) { 
            if (parentRow == null) {
                SetParentRowToDBNull();
                return;
            } 

            foreach (DataRelation relation in _table.ParentRelations) { 
                if (relation.Nested || setNonNested) { 
                    if (relation.ParentKey.Table == parentRow._table) {
                        object[] parentKeyValues = parentRow.GetKeyValues(relation.ParentKey); 
                        this.SetKeyValues(relation.ChildKey, parentKeyValues);

                        if (relation.Nested) {
                            if (parentRow._table == _table) 
                                this.CheckForLoops(relation);
                            else 
                                this.GetParentRow(relation); 
                        }
                    } 
                }
            }
        }
        ///  
        ///    [To be supplied.]
        ///  
        public void SetParentRow(DataRow parentRow) { 
            SetNestedParentRow(parentRow, true);
        } 

        /// 
        ///    
        ///       Sets current row's parent row with specified relation. 
        ///    
        ///  
        public void SetParentRow(DataRow parentRow, DataRelation relation) { 
            if (relation == null) {
                SetParentRow(parentRow); 
                return;
            }

            if (parentRow == null) { 
                SetParentRowToDBNull(relation);
                return; 
            } 

            //if (-1 == rowID) 
            //    throw ExceptionBuilder.ChildRowNotInTheTable();

            //if (-1 == parentRow.rowID)
            //    throw ExceptionBuilder.ParentRowNotInTheTable(); 

            if (_table.DataSet != parentRow._table.DataSet) 
                throw ExceptionBuilder.ParentRowNotInTheDataSet(); 

            if (relation.ChildKey.Table != _table) 
                throw ExceptionBuilder.SetParentRowTableMismatch(relation.ChildKey.Table.TableName, _table.TableName);

            if (relation.ParentKey.Table != parentRow._table)
                throw ExceptionBuilder.SetParentRowTableMismatch(relation.ParentKey.Table.TableName, parentRow._table.TableName); 

            object[] parentKeyValues = parentRow.GetKeyValues(relation.ParentKey); 
            this.SetKeyValues(relation.ChildKey, parentKeyValues); 
        }
 
        internal void SetParentRowToDBNull() {
            //if (-1 == rowID)
            //    throw ExceptionBuilder.ChildRowNotInTheTable();
 
            foreach (DataRelation relation in _table.ParentRelations)
                SetParentRowToDBNull(relation); 
        } 

        internal void SetParentRowToDBNull(DataRelation relation) { 
            Debug.Assert(relation != null, "The relation should not be null here.");

            //if (-1 == rowID)
            //    throw ExceptionBuilder.ChildRowNotInTheTable(); 

            if (relation.ChildKey.Table != _table) 
                throw ExceptionBuilder.SetParentRowTableMismatch(relation.ChildKey.Table.TableName, _table.TableName); 

 
            object[] parentKeyValues = new object[1];
            parentKeyValues[0] = DBNull.Value;
            this.SetKeyValues(relation.ChildKey, parentKeyValues);
        } 
        public void SetAdded(){
            if (this.RowState == DataRowState.Unchanged) { 
                _table.SetOldRecord(this, -1); 
            }
            else { 
                throw ExceptionBuilder.SetAddedAndModifiedCalledOnnonUnchanged();
            }
        }
 
        public void SetModified(){
            if (this.RowState == DataRowState.Unchanged) { 
                tempRecord = _table.NewRecord(newRecord); 
                if (tempRecord != -1) {
                    SetNewRecord(tempRecord); 
                }
            }
            else {
                throw ExceptionBuilder.SetAddedAndModifiedCalledOnnonUnchanged(); 
            }
        } 
 
/*
    RecordList contains the empty column storage needed. We need to copy the existing record values into this storage. 
*/
        internal int CopyValuesIntoStore(ArrayList storeList, ArrayList nullbitList, int storeIndex) {
            int recordCount = 0;
            if (oldRecord != -1) {//Copy original record for the row in Unchanged, Modified, Deleted state. 
                for (int i = 0; i < _columns.Count; i++) {
                    _columns[i].CopyValueIntoStore(oldRecord, storeList[i], (BitArray) nullbitList[i], storeIndex); 
                } 
                recordCount++;
                storeIndex++; 
            }

            DataRowState state = RowState;
            if ((DataRowState.Added == state) || (DataRowState.Modified == state)) { //Copy current record for the row in Added, Modified state. 
                for (int i = 0; i < _columns.Count; i++) {
                    _columns[i].CopyValueIntoStore(newRecord, storeList[i], (BitArray) nullbitList[i], storeIndex); 
                } 
                recordCount++;
                storeIndex++; 
            }

            if (-1 != tempRecord) {//Copy temp record for the row in edit mode.
                for (int i = 0; i < _columns.Count; i++) { 
                    _columns[i].CopyValueIntoStore(tempRecord, storeList[i], (BitArray)nullbitList[i], storeIndex);
                } 
                recordCount++; 
                storeIndex++;
            } 
            return recordCount;
        }
 		
        [Conditional("DEBUG")] 
        private void VerifyValueFromStorage(DataColumn column, DataRowVersion version, object valueFromStorage) {
            if (column.DataExpression != null && !inChangingEvent && tempRecord == -1) 
            { 
                // for unchanged rows, check current if original is asked for.
                // this is because by design, there is only single storage for an unchanged row. 
                if (version == DataRowVersion.Original && oldRecord == newRecord) {
                    version = DataRowVersion.Current;
                }
					 
                Debug.Assert(valueFromStorage.Equals(column.DataExpression.Evaluate(this, version)),
                    "Value from storage does lazily computed expression value"); 
            } 
        }
    } 

#if WINFSInternalOnly
    internal
#else 
    public
#endif 
    sealed class DataRowBuilder { 
        internal readonly DataTable   _table;
        internal int                  _record; 

        internal DataRowBuilder(DataTable table, int record) {
            _table = table;
            _record = record; 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data {
    using System; 
    using System.Collections;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Xml;
 
 
    /// 
    /// Represents a row of data in a . 
    /// 
#if WINFSInternalOnly
    internal
#else 
    public
#endif 
    class DataRow { 
        private readonly DataTable _table;
        private readonly DataColumnCollection _columns; 

        internal int  oldRecord = -1;
        internal int  newRecord = -1;
        internal int  tempRecord; 
        internal int  _rowID = -1;
 
        internal DataRowAction _action; 

        internal bool  inChangingEvent; 
        internal bool  inDeletingEvent;
        internal bool  inCascade;

        private DataColumn _lastChangedColumn; // last successfully changed column 
        private int _countColumnChange;        // number of columns changed during edit mode
 
        private DataError  error; 
        private object    _element;
 
        private int _rbTreeNodeId; // if row is not detached, Id used for computing index in rows collection

        private static int _objectTypeCount; // Bid counter
        internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        ///     
        ///       Initializes a new instance of the DataRow.
        ///     
        ///    
        ///       Constructs a row from the builder. Only for internal usage..
        ///    
        ///  
        protected internal DataRow (DataRowBuilder builder) {
            tempRecord = builder._record; 
            _table = builder._table; 
            _columns = _table.Columns;
        } 

        internal XmlBoundElement  Element {
            get {
                return (XmlBoundElement) _element; 
            }
            set { 
                _element = value; 
            }
        } 

        internal DataColumn LastChangedColumn {
            get { // last successfully changed column or if multiple columns changed: null
                if (_countColumnChange != 1) { 
                    return null;
                } 
                return _lastChangedColumn; 
            }
            set { 
                _countColumnChange++;
                _lastChangedColumn = value;
            }
        } 

        internal bool HasPropertyChanged { 
            get { return (0 < _countColumnChange); } 
        }
 
        internal int RBTreeNodeId {
            get {
                return _rbTreeNodeId;
            } 
            set {
                Bid.Trace(" %d#, value=%d\n", ObjectID, value); 
                _rbTreeNodeId = value; 
            }
        } 

        /// 
        ///    Gets or sets the custom error description for a row.
        ///  
        public string RowError {
            get { 
                return(error == null ? String.Empty :error.Text); 
            }
            set { 
                Bid.Trace(" %d#, value='%ls'\n", ObjectID, value);
                if (error == null) {
                    if (!Common.ADP.IsEmpty(value)) {
                        error = new DataError(value); 
                    }
                    RowErrorChanged(); 
                } 
                else if(error.Text != value) {
                    error.Text = value; 
                    RowErrorChanged();
                }
            }
        } 

        private void RowErrorChanged() { 
            // We don't know wich record was used by view index. try to use both. 
            if (oldRecord != -1)
                _table.RecordChanged(oldRecord); 
            if (newRecord != -1)
                _table.RecordChanged(newRecord);
        }
 
        internal int rowID {
            get { 
                return _rowID; 
            }
            set { 
                ResetLastChangedColumn();
                _rowID = value;
            }
        } 

        ///  
        ///    Gets the current state of the row in regards to its relationship to the table. 
        /// 
        public DataRowState RowState { 
            get {
                /*
                if (oldRecord == -1 && newRecord == -1)
                    state = DataRowState.Detached; // 2 
                else if (oldRecord == newRecord)
                    state = DataRowState.Unchanged; // 2 
                else if (oldRecord == -1) 
                    state = DataRowState.Added; // 4
                else if (newRecord == -1) 
                    state = DataRowState.Deleted; // 4
                else
                    state = DataRowState.Modified; // 4
                */ 
                if (oldRecord == newRecord) {
                    if (oldRecord == -1) { 
                        return DataRowState.Detached; // 2 
                    }
                    if (0 < _columns.ColumnsImplementingIChangeTrackingCount) { 
                        foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) {
                            object value = this[dc];
                            if ((DBNull.Value != value) && ((IChangeTracking)value).IsChanged) {
                                return DataRowState.Modified; // 3 + _columns.columnsImplementingIChangeTracking.Count 
                            }
                        } 
                    } 
                    return DataRowState.Unchanged; // 3
                } 
                else if (oldRecord == -1) {
                    return DataRowState.Added; // 2
                }
                else if (newRecord == -1) { 
                    return DataRowState.Deleted; // 3
                } 
                return DataRowState.Modified; // 3 

            } 
        }

        /// 
        /// Gets the  
        /// for which this row has a schema.
        ///  
        public DataTable Table { 
            get {
                return _table; 
            }
        }

        ///  
        ///    Gets or sets the data stored in the column specified by index.
        ///  
        public object this[int columnIndex] { 
            get {
                DataColumn column = _columns[columnIndex]; 
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, DataRowVersion.Default, column[record]);
                return column[record]; 
            }
            set { 
                DataColumn column = _columns[columnIndex]; 
                this[column] = value;
            } 
        }

        internal void CheckForLoops(DataRelation rel){
            // don't check for loops in the diffgram 
            // because there may be some holes in the rowCollection
            // and index creation may fail. The check will be done 
            // after all the loading is done _and_ we are sure there 
            // are no holes in the collection.
            if (_table.fInLoadDiffgram || (_table.DataSet != null && _table.DataSet.fInLoadDiffgram)) 
              return;
            int count = _table.Rows.Count, i = 0;
            // need to optimize this for count > 100
            DataRow parent = this.GetParentRow(rel); 
            while (parent != null) {
                if ((parent == this) || (i>count)) 
                    throw ExceptionBuilder.NestedCircular(_table.TableName); 
                i++;
                parent = parent.GetParentRow(rel); 
            }
        }

        internal int GetNestedParentCount() { 
            int count = 0;
            DataRelation[] nestedParentRelations = _table.NestedParentRelations; 
            foreach(DataRelation rel in nestedParentRelations) { 
                if (rel == null) // don't like this but done for backward code compatability
                    continue; 
                if (rel.ParentTable == _table) // self-nested table
                    this.CheckForLoops(rel);
                DataRow row = this.GetParentRow(rel);
                if (row != null) { 
                    count++;
                } 
            } 
            return count ;
            // Rule 1: At all times, only ONE FK  "(in a row) can be non-Null 
            // we wont allow a row to have multiple parents, as we cant handle it , also in diffgram
        }

        ///  
        ///    Gets or sets the data stored in the column specified by
        ///       name. 
        ///  
        public object this[string columnName] {
            get { 
                DataColumn column = GetDataColumn(columnName);
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, DataRowVersion.Default, column[record]); 
                return column[record];
            } 
            set { 
                DataColumn column = GetDataColumn(columnName);
                this[column] = value; 
            }
        }

        ///  
        ///    Gets or sets
        ///       the data stored in the specified . 
        ///  
        public object this[DataColumn column] {
            get { 
                CheckColumn(column);
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, DataRowVersion.Default, column[record]); 
                return column[record];
            } 
            set { 
                CheckColumn(column);
                if (inChangingEvent) { 
                    throw ExceptionBuilder.EditInRowChanging();
                }
                if ((-1 != rowID) && column.ReadOnly) {
                    throw ExceptionBuilder.ReadOnly(column.ColumnName); 
                }
 
                // allow users to tailor the proposed value, or throw an exception. 
                // note we intentionally do not try/catch this event.
                // note: we also allow user to do anything at this point 
                // infinite loops are possible if user calls Item or ItemArray during the event
                DataColumnChangeEventArgs e = null;
                if (_table.NeedColumnChangeEvents) {
                    e = new DataColumnChangeEventArgs(this, column, value); 
                    _table.OnColumnChanging(e);
                } 
 
                if (column.Table != _table) {
                    // user removed column from table during OnColumnChanging event 
                    throw ExceptionBuilder.ColumnNotInTheTable(column.ColumnName, _table.TableName);
                }
                if ((-1 != rowID) && column.ReadOnly) {
                    // user adds row to table during OnColumnChanging event 
                    throw ExceptionBuilder.ReadOnly(column.ColumnName);
                } 
 
                object proposed = ((null != e) ? e.ProposedValue : value);
                if (null == proposed) { 
                    if (column.IsValueType) { // WebData 105963
                        throw ExceptionBuilder.CannotSetToNull(column);
                    }
                    proposed = DBNull.Value; 
                }
 
                bool immediate = BeginEditInternal(); 
                try {
                    int record = GetProposedRecordNo(); 
                    _table.recordManager.VerifyRecord(record, this);
                    column[record] = proposed;
                }
                catch (Exception e1){ 
                    //
                    if (Common.ADP.IsCatchableOrSecurityExceptionType(e1)) { 
                        if (immediate) { 
                            Debug.Assert(!inChangingEvent, "how are we in a changing event to cancel?");
                            Debug.Assert(-1 != tempRecord, "how no propsed record to cancel?"); 
                            CancelEdit(); // WebData 107154
                        }
                    }
                    throw; 
                }
                LastChangedColumn = column; 
 
                // note: we intentionally do not try/catch this event.
                // infinite loops are possible if user calls Item or ItemArray during the event 
                if (null != e) {
                    _table.OnColumnChanged(e); // user may call CancelEdit or EndEdit
                }
 
                if (immediate) {
                    Debug.Assert(!inChangingEvent, "how are we in a changing event to end?"); 
                    EndEdit(); 
                }
            } 
        }

        /// 
        ///    Gets the data stored 
        ///       in the column, specified by index and version of the data to retrieve.
        ///  
        public object this[int columnIndex, DataRowVersion version] { 
            get {
                DataColumn column = _columns[columnIndex]; 
                int record = GetRecordFromVersion(version);
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, version, column[record]);
                return column[record]; 
            }
        } 
 
        /// 
        ///     Gets the specified version of data stored in 
        ///       the named column.
        /// 
        public object this[string columnName, DataRowVersion version] {
            get { 
                DataColumn column = GetDataColumn(columnName);
                int record = GetRecordFromVersion(version); 
                _table.recordManager.VerifyRecord(record, this); 
                VerifyValueFromStorage(column, version, column[record]);
                return column[record]; 
            }
        }

        ///  
        /// Gets the specified version of data stored in the specified .
        ///  
        public object this[DataColumn column, DataRowVersion version] { 
            get {
                CheckColumn(column); 
                int record = GetRecordFromVersion(version);
                _table.recordManager.VerifyRecord(record, this);
                VerifyValueFromStorage(column, version, column[record]);
                return column[record]; 
            }
        } 
 
        /// 
        ///    Gets 
        ///       or sets all of the values for this row through an array.
        /// 
        public object[] ItemArray {
            get { 
                int record = GetDefaultRecord();
                _table.recordManager.VerifyRecord(record, this); 
                object[] values = new object[_columns.Count]; 
                for (int i = 0; i < values.Length; i++) {
                    DataColumn column = _columns[i]; 
                    VerifyValueFromStorage(column, DataRowVersion.Default, column[record]);
                    values[i] = column[record];
                }
                return values; 
            }
            set { 
                if (null == value) { // WebData 104372 
                    throw ExceptionBuilder.ArgumentNull("ItemArray");
                } 
                if (_columns.Count < value.Length) {
                    throw ExceptionBuilder.ValueArrayLength();
                }
                DataColumnChangeEventArgs e = null; 
                if (_table.NeedColumnChangeEvents) {
                    e = new DataColumnChangeEventArgs(this); 
                } 
                bool immediate = BeginEditInternal();
 
                for (int i = 0; i < value.Length; ++i) {
                    // Empty means don't change the row.
                    if (null != value[i]) {
                        // may throw exception if user removes column from table during event 
                        DataColumn column = _columns[i];
 
                        if ((-1 != rowID) && column.ReadOnly) { 
                            throw ExceptionBuilder.ReadOnly(column.ColumnName);
                        } 

                        // allow users to tailor the proposed value, or throw an exception.
                        // note: we intentionally do not try/catch this event.
                        // note: we also allow user to do anything at this point 
                        // infinite loops are possible if user calls Item or ItemArray during the event
                        if (null != e) { 
                            e.InitializeColumnChangeEvent(column, value[i]); 
                            _table.OnColumnChanging(e);
                        } 

                        if (column.Table != _table) {
                            // user removed column from table during OnColumnChanging event
                            throw ExceptionBuilder.ColumnNotInTheTable(column.ColumnName, _table.TableName); 
                        }
                        if ((-1 != rowID) && column.ReadOnly) { 
                            // user adds row to table during OnColumnChanging event 
                            throw ExceptionBuilder.ReadOnly(column.ColumnName);
                        } 
                        if (tempRecord == -1) {
                            // user affected CancelEdit or EndEdit during OnColumnChanging event of the last value
                            BeginEditInternal();
                        } 

                        object proposed = (null != e) ? e.ProposedValue : value[i]; 
                        if (null == proposed) { 
                            if (column.IsValueType) { // WebData 105963
                                throw ExceptionBuilder.CannotSetToNull(column); 
                            }
                            proposed = DBNull.Value;
                        }
 
                        try {
                            // must get proposed record after each event because user may have 
                            // called EndEdit(), AcceptChanges(), BeginEdit() during the event 
                            int record = GetProposedRecordNo();
                            _table.recordManager.VerifyRecord(record, this); 
                            column[record] = proposed;
                        }
                        catch (Exception e1) {
                            // 
                            if (Common.ADP.IsCatchableOrSecurityExceptionType(e1)) {
                                if (immediate) { 
                                    Debug.Assert(!inChangingEvent, "how are we in a changing event to cancel?"); 
                                    Debug.Assert(-1 != tempRecord, "how no propsed record to cancel?");
                                    CancelEdit(); // WebData 107154 
                                }
                            }
                            throw;
                        } 
                        LastChangedColumn = column;
 
                        // note: we intentionally do not try/catch this event. 
                        // infinite loops are possible if user calls Item or ItemArray during the event
                        if (null != e) { 
                            _table.OnColumnChanged(e);  // user may call CancelEdit or EndEdit
                        }
                    }
                } 

                // proposed breaking change: if (immediate){ EndEdit(); } because table currently always fires RowChangedEvent 
                Debug.Assert(!inChangingEvent, "how are we in a changing event to end?"); 
                EndEdit();
            } 
        }

        /// 
        ///    Commits all the changes made to this row 
        ///       since the last time  was called.
        ///  
        public void AcceptChanges() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                EndEdit();

                if (this.RowState != DataRowState.Detached && this.RowState != DataRowState.Deleted) { 
                    if (_columns.ColumnsImplementingIChangeTrackingCount > 0) {
                        foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) { 
                            object value = this[dc]; 
                            if (DBNull.Value != value) {
                                IChangeTracking tracking = (IChangeTracking)value; 
                                if (tracking.IsChanged) {
                                    tracking.AcceptChanges();
                                }
                            } 
                        }
                    } 
                } 
                _table.CommitRow(this);
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        ///  
        /// Begins an edit operation on a object. 
        /// 
        [ 
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ]
        public void BeginEdit() {
            BeginEditInternal(); 
        }
 
        private bool BeginEditInternal() { 
            if (inChangingEvent) {
                throw ExceptionBuilder.BeginEditInRowChanging(); 
            }
            if (tempRecord != -1) {
                if (tempRecord < _table.recordManager.LastFreeRecord) {
                    return false; // we will not call EndEdit 
                }
                else { 
                    // partial fix for detached row after Table.Clear scenario 
                    // in debug, it will have asserted earlier, but with this
                    // it will go get a new record for editing 
                    tempRecord = -1;
                }
                // shifted VerifyRecord to first make the correction, then verify
                _table.recordManager.VerifyRecord(tempRecord, this); 
            }
 
            if (oldRecord != -1 && newRecord == -1) { 
                throw ExceptionBuilder.DeletedRowInaccessible();
            } 

            //

            ResetLastChangedColumn(); // shouldn't have to do this 

            tempRecord = _table.NewRecord(newRecord); 
            Debug.Assert(-1 != tempRecord, "missing temp record"); 
            Debug.Assert(0 == _countColumnChange, "unexpected column change count");
            Debug.Assert(null == _lastChangedColumn, "unexpected last column change"); 
            return true;
        }

        ///  
        ///    Cancels the current edit on the row.
        ///  
        [ 
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ] 
        public void CancelEdit() {
            if (inChangingEvent) {
                throw ExceptionBuilder.CancelEditInRowChanging();
            } 

            _table.FreeRecord(ref tempRecord); 
            Debug.Assert(-1 == tempRecord, "unexpected temp record"); 
            ResetLastChangedColumn();
        } 

        private void CheckColumn(DataColumn column) {
            if (column == null) {
                throw ExceptionBuilder.ArgumentNull("column"); 
            }
 
            if (column.Table != _table) { 
                throw ExceptionBuilder.ColumnNotInTheTable(column.ColumnName, _table.TableName);
            } 
        }

        /// 
        /// Throws a RowNotInTableException if row isn't in table. 
        /// 
        internal void CheckInTable() { 
            if (rowID == -1) { 
                throw ExceptionBuilder.RowNotInTheTable();
            } 
        }

        /// 
        ///    Deletes the row. 
        /// 
        public void Delete() { 
            if (inDeletingEvent) { 
                throw ExceptionBuilder.DeleteInRowDeleting();
            } 

            if (newRecord == -1)
                return;
 
            _table.DeleteRow(this);
        } 
 
        /// 
        ///    Ends the edit occurring on the row. 
        /// 
        [
        EditorBrowsableAttribute(EditorBrowsableState.Advanced),
        ] 
        public void EndEdit() {
            if (inChangingEvent) { 
                throw ExceptionBuilder.EndEditInRowChanging(); 
            }
 
            if (newRecord == -1) {
                return; // this is meaningless, detatched row case
            }
 
            if (tempRecord != -1) {
                //int record = tempRecord; 
                //tempRecord = -1; 
                try {
                    SetNewRecord(tempRecord); 
                }
                finally {
                    // a constraint violation may be thrown during SetNewRecord
                    ResetLastChangedColumn(); 
                }
            } 
        } 

        ///  
        ///    Sets the error description for a column specified by index.
        /// 
        public void SetColumnError(int columnIndex, string error) {
            DataColumn column = _columns[columnIndex]; 
            if (column == null)
                throw ExceptionBuilder.ColumnOutOfRange(columnIndex); 
 
            SetColumnError(column, error);
        } 

        /// 
        ///    Sets
        ///       the error description for a column specified by name. 
        /// 
        public void SetColumnError(string columnName, string error) { 
            DataColumn column = GetDataColumn(columnName); 
            SetColumnError(column, error);
        } 

        /// 
        /// Sets the error description for a column specified as a .
        ///  
        public void SetColumnError(DataColumn column, string error) {
            CheckColumn(column); 
 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, column=%d, error='%ls'\n", ObjectID, column.ObjectID, error); 
            try {
                if (this.error == null)  this.error = new DataError();
                if(GetColumnError(column) != error) {
                    this.error.SetColumnError(column, error); 
                    RowErrorChanged();
                } 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        ///    Gets the error description for the column specified
        ///       by index. 
        ///  
        public string GetColumnError(int columnIndex) {
            DataColumn column = _columns[columnIndex]; 
            return GetColumnError(column);
        }

        ///  
        ///    Gets the error description for a column, specified by name.
        ///  
        public string GetColumnError(string columnName) { 
            DataColumn column = GetDataColumn(columnName);
            return GetColumnError(column); 
        }

        /// 
        ///    Gets the error description of 
        ///       the specified .
        ///  
        public string GetColumnError(DataColumn column) { 
            CheckColumn(column);
            if (error == null)  error = new DataError(); 
            return error.GetColumnError(column);
        }

        ///  
        /// Clears the errors for the row, including the 
        /// and errors set with  
        ///  
        public void ClearErrors() {
            if (error != null) { 
                error.Clear();
                RowErrorChanged();
            }
        } 

        internal void ClearError(DataColumn column) { 
            if (error != null) { 
                error.Clear(column);
                RowErrorChanged(); 
            }
        }

        ///  
        ///    Gets a value indicating whether there are errors in a columns collection.
        ///  
        public bool HasErrors { 
            get {
                return(error == null ? false : error.HasErrors); 
            }
        }

        ///  
        ///    Gets an array of columns that have errors.
        ///  
        public DataColumn[] GetColumnsInError() { 
            if (error == null)
                return DataTable.zeroColumns; 
            else
                return error.GetColumnsInError();
        }
 

        public DataRow[] GetChildRows(string relationName) { 
            return GetChildRows(_table.ChildRelations[relationName], DataRowVersion.Default); 
        }
 
        public DataRow[] GetChildRows(string relationName, DataRowVersion version) {
            return GetChildRows(_table.ChildRelations[relationName], version);
        }
 
        /// 
        /// Gets the child rows of this  using the 
        ///    specified  
        ///    .
        ///  
        public DataRow[] GetChildRows(DataRelation relation) {
            return GetChildRows(relation, DataRowVersion.Default);
        }
 
        /// 
        /// Gets the child rows of this  using the specified  and the specified  
        ///  
        public DataRow[] GetChildRows(DataRelation relation, DataRowVersion version) {
            if (relation == null) 
                return _table.NewRowArray(0);

            //if (-1 == rowID)
            //    throw ExceptionBuilder.RowNotInTheTable(); 

            if (relation.DataSet != _table.DataSet) 
                throw ExceptionBuilder.RowNotInTheDataSet(); 
            if (relation.ParentKey.Table != _table)
                throw ExceptionBuilder.RelationForeignTable(relation.ParentTable.TableName, _table.TableName); 
            return DataRelation.GetChildRows(relation.ParentKey, relation.ChildKey, this, version);
        }

        internal DataColumn GetDataColumn(string columnName) { 
            DataColumn column = _columns[columnName];
            if (null != column) { 
                return column; 
            }
            throw ExceptionBuilder.ColumnNotInTheTable(columnName, _table.TableName); 
        }

        public DataRow GetParentRow(string relationName) {
            return GetParentRow(_table.ParentRelations[relationName], DataRowVersion.Default); 
        }
 
        public DataRow GetParentRow(string relationName, DataRowVersion version) { 
            return GetParentRow(_table.ParentRelations[relationName], version);
        } 

        /// 
        /// Gets the parent row of this  using the specified  .
        ///  
        public DataRow GetParentRow(DataRelation relation) {
            return GetParentRow(relation, DataRowVersion.Default); 
        } 

        ///  
        /// Gets the parent row of this 
        /// using the specified  and .
        /// 
        public DataRow GetParentRow(DataRelation relation, DataRowVersion version) { 
            if (relation == null)
                return null; 
 
            //if (-1 == rowID)
            //    throw ExceptionBuilder.RowNotInTheTable(); 

            if (relation.DataSet != _table.DataSet)
                throw ExceptionBuilder.RelationForeignRow();
 
            if (relation.ChildKey.Table != _table)
                throw ExceptionBuilder.GetParentRowTableMismatch(relation.ChildTable.TableName, _table.TableName); 
 
            return DataRelation.GetParentRow(relation.ParentKey, relation.ChildKey, this, version);
        } 
        // a multiple nested child table's row can have only one non-null FK per row. So table has multiple
        // parents, but a row can have only one parent. Same nested row cannot below to 2 parent rows.
        internal DataRow GetNestedParentRow(DataRowVersion version) {
            // 1) Walk over all FKs and get the non-null. 2) Get the relation. 3) Get the parent Row. 
            DataRelation[] nestedParentRelations = _table.NestedParentRelations;
            foreach(DataRelation rel in nestedParentRelations) { 
                if (rel == null) // don't like this but done for backward code compatability 
                    continue;
                if (rel.ParentTable == _table) // self-nested table 
                    this.CheckForLoops(rel);
                DataRow row = this.GetParentRow(rel, version);
                if (row != null) {
                    return row; 
                }
            } 
            return null;// Rule 1: At all times, only ONE FK  "(in a row) can be non-Null 

        } 
        // No Nested in 1-many

        /// 
        ///    [To be supplied.] 
        /// 
        public DataRow[] GetParentRows(string relationName) { 
            return GetParentRows(_table.ParentRelations[relationName], DataRowVersion.Default); 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        public DataRow[] GetParentRows(string relationName, DataRowVersion version) { 
            return GetParentRows(_table.ParentRelations[relationName], version);
        } 
 
        /// 
        ///     
        ///       Gets the parent rows of this  using the specified  .
        ///    
        /// 
        public DataRow[] GetParentRows(DataRelation relation) { 
            return GetParentRows(relation, DataRowVersion.Default);
        } 
 
        /// 
        ///     
        ///       Gets the parent rows of this  using the specified  .
        ///    
        /// 
        public DataRow[] GetParentRows(DataRelation relation, DataRowVersion version) { 
            if (relation == null)
                return _table.NewRowArray(0); 
 
            //if (-1 == rowID)
            //    throw ExceptionBuilder.RowNotInTheTable(); 

            if (relation.DataSet != _table.DataSet)
                throw ExceptionBuilder.RowNotInTheDataSet();
 
            if (relation.ChildKey.Table != _table)
                throw ExceptionBuilder.GetParentRowTableMismatch(relation.ChildTable.TableName, _table.TableName); 
 
            return DataRelation.GetParentRows(relation.ParentKey, relation.ChildKey, this, version);
        } 

        internal object[] GetColumnValues(DataColumn[] columns) {
            return GetColumnValues(columns, DataRowVersion.Default);
        } 

        internal object[] GetColumnValues(DataColumn[] columns, DataRowVersion version) { 
            DataKey key = new DataKey(columns, false); // temporary key, don't copy columns 
            return GetKeyValues(key, version);
        } 

        internal object[] GetKeyValues(DataKey key) {
            int record = GetDefaultRecord();
            return key.GetKeyValues(record); 
        }
 
        internal object[] GetKeyValues(DataKey key, DataRowVersion version) { 
            int record = GetRecordFromVersion(version);
            return key.GetKeyValues(record); 
        }

        internal int GetCurrentRecordNo() {
            if (newRecord == -1) 
                throw ExceptionBuilder.NoCurrentData();
            return newRecord; 
        } 

        internal int GetDefaultRecord() { 
            if (tempRecord != -1)
                return tempRecord;
            if (newRecord != -1) {
                return newRecord; 
            }
            // If row has oldRecord - this is deleted row. 
            if (oldRecord == -1) 
                throw ExceptionBuilder.RowRemovedFromTheTable();
            else 
                throw ExceptionBuilder.DeletedRowInaccessible();
        }

        internal int GetOriginalRecordNo() { 
            if (oldRecord == -1)
                throw ExceptionBuilder.NoOriginalData(); 
            return oldRecord; 
        }
 
        private int GetProposedRecordNo() {
            if (tempRecord == -1)
                throw ExceptionBuilder.NoProposedData();
            return tempRecord; 
        }
 
        internal int GetRecordFromVersion(DataRowVersion version) { 
            switch (version) {
                case DataRowVersion.Original: 
                    return GetOriginalRecordNo();
                case DataRowVersion.Current:
                    return GetCurrentRecordNo();
                case DataRowVersion.Proposed: 
                    return GetProposedRecordNo();
                case DataRowVersion.Default: 
                    return GetDefaultRecord(); 
                default:
                    throw ExceptionBuilder.InvalidRowVersion(); 
            }
        }

        internal DataRowVersion GetDefaultRowVersion(DataViewRowState viewState) { 
            if (oldRecord == newRecord) {
                if (oldRecord == -1) { 
                    // should be DataView.addNewRow 
                    return DataRowVersion.Default;
                } 
                Debug.Assert(0 != (DataViewRowState.Unchanged & viewState), "not DataViewRowState.Unchanged");
                return DataRowVersion.Default;
            }
            else if (oldRecord == -1) { 
                Debug.Assert(0 != (DataViewRowState.Added & viewState), "not DataViewRowState.Added");
                return DataRowVersion.Default; 
            } 
            else if (newRecord == -1) {
                Debug.Assert(0 != (DataViewRowState.Deleted & viewState), "not DataViewRowState.Deleted"); 
                return DataRowVersion.Original;
            }
            else if (0 != (DataViewRowState.ModifiedCurrent & viewState)) {
                return DataRowVersion.Default; 
            }
            Debug.Assert(0 != (DataViewRowState.ModifiedOriginal & viewState), "not DataViewRowState.ModifiedOriginal"); 
            return DataRowVersion.Original; 
        }
 
        internal DataViewRowState GetRecordState(int record) {
            if (record == -1)
                return DataViewRowState.None;
            if (record == oldRecord && record == newRecord) 
                return DataViewRowState.Unchanged;
            if (record == oldRecord) 
                return(newRecord != -1) ? DataViewRowState.ModifiedOriginal : DataViewRowState.Deleted; 
            if (record == newRecord)
                return(oldRecord != -1) ? DataViewRowState.ModifiedCurrent : DataViewRowState.Added; 
            return DataViewRowState.None;
        }

        internal bool HasKeyChanged(DataKey key) { 
            return HasKeyChanged(key, DataRowVersion.Current, DataRowVersion.Proposed);
        } 
 
        internal bool HasKeyChanged(DataKey key, DataRowVersion version1, DataRowVersion version2) {
            if (!HasVersion(version1) || !HasVersion(version2)) 
                return true;
            return !key.RecordsEqual(GetRecordFromVersion(version1), GetRecordFromVersion(version2));
        }
 
        /// 
        ///     
        ///       Gets a value indicating whether a specified version exists. 
        ///    
        ///  
        public bool HasVersion(DataRowVersion version) {
            switch (version) {
                case DataRowVersion.Original:
                    return(oldRecord != -1); 
                case DataRowVersion.Current:
                    return(newRecord != -1); 
                case DataRowVersion.Proposed: 
                    return(tempRecord != -1);
                case DataRowVersion.Default: 
                    return(tempRecord != -1 || newRecord != -1);
                default:
                    throw ExceptionBuilder.InvalidRowVersion();
            } 
        }
 
        internal bool HasChanges() { 
            if (!HasVersion(DataRowVersion.Original) || !HasVersion(DataRowVersion.Current)) {
                return true; // if does not have original, its added row, if does not have current, its deleted row so it has changes 
            }
            foreach(DataColumn dc in Table.Columns) {
                if (dc.Compare(oldRecord, newRecord) != 0) {
                    return true; 
                }
            } 
            return false; 
        }
 
        internal bool HaveValuesChanged(DataColumn[] columns) {
            return HaveValuesChanged(columns, DataRowVersion.Current, DataRowVersion.Proposed);
        }
 
        internal bool HaveValuesChanged(DataColumn[] columns, DataRowVersion version1, DataRowVersion version2) {
            for (int i = 0; i < columns.Length; i++) { 
                CheckColumn(columns[i]); 
            }
            DataKey key = new DataKey(columns, false); // temporary key, don't copy columns 
            return HasKeyChanged(key, version1, version2);
        }

        ///  
        ///    
        ///       Gets 
        ///       a value indicating whether the column at the specified index contains a 
        ///       null value.
        ///     
        /// 
        public bool IsNull(int columnIndex) {
            DataColumn column = _columns[columnIndex];
            int record = GetDefaultRecord(); 
            return column.IsNull(record);
        } 
 
        /// 
        ///     
        ///       Gets a value indicating whether the named column contains a null value.
        ///    
        /// 
        public bool IsNull(string columnName) { 
            DataColumn column = GetDataColumn(columnName);
            int record = GetDefaultRecord(); 
            return column.IsNull(record); 
        }
 
        /// 
        ///    
        ///       Gets a value indicating whether the specified 
        ///       contains a null value. 
        ///    
        ///  
        public bool IsNull(DataColumn column) { 
            CheckColumn(column);
            int record = GetDefaultRecord(); 
            return column.IsNull(record);
        }

        ///  
        ///    [To be supplied.]
        ///  
        public bool IsNull(DataColumn column, DataRowVersion version) { 
            CheckColumn(column);
            int record = GetRecordFromVersion(version); 
            return column.IsNull(record);
        }

        ///  
        ///    
        ///       Rejects all changes made to the row since  
        ///       was last called. 
        ///    
        ///  
        public void RejectChanges() {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try { 
                if (this.RowState != DataRowState.Detached) {
                    if (_columns.ColumnsImplementingIChangeTrackingCount != _columns.ColumnsImplementingIRevertibleChangeTrackingCount) { 
                        foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) { 
                            if (!dc.ImplementsIRevertibleChangeTracking) {
                                object value = null; 
                                if (this.RowState != DataRowState.Deleted)
                                    value = this[dc];
                                else
                                    value = this[dc, DataRowVersion.Original]; 
                                if (DBNull.Value != value){
                                    if (((IChangeTracking)value).IsChanged) { 
                                        throw ExceptionBuilder.UDTImplementsIChangeTrackingButnotIRevertible(dc.DataType.AssemblyQualifiedName); 
                                    }
                                } 
                            }
                        }
                    }
                    foreach(DataColumn dc in _columns.ColumnsImplementingIChangeTracking) { 
                        object value = null;
                         if (this.RowState != DataRowState.Deleted) 
                            value = this[dc]; 
                         else
                            value = this[dc, DataRowVersion.Original]; 
                        if (DBNull.Value != value) {
                            IChangeTracking tracking = (IChangeTracking)value;
                            if (tracking.IsChanged) {
                                ((IRevertibleChangeTracking)value).RejectChanges(); 
                            }
                        } 
                    } 
                }
                _table.RollbackRow(this); 
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
        internal void ResetLastChangedColumn() { 
            _lastChangedColumn = null;
            _countColumnChange = 0; 
        }

        internal void SetKeyValues(DataKey key, object[] keyValues) {
            bool fFirstCall = true; 
            bool immediate = (tempRecord == -1);
 
            for (int i = 0; i < keyValues.Length; i++) { 
                object value = this[key.ColumnsReference[i]];
                if (!value.Equals(keyValues[i])) { 
                    if (immediate && fFirstCall) {
                        fFirstCall = false;
                        BeginEditInternal();
                    } 
                    this[key.ColumnsReference[i]] = keyValues[i];
                } 
            } 
            if (!fFirstCall)
                EndEdit(); 
        }

        // if it's a detached row, we can't add it, we'll just keep it as temp.
        internal void SetNewRecord(int record) { 
            //Debug.Assert(oldRecord != -1 || newRecord != -1, "You can't call SetNewRecord on a detached row.");
            _table.SetNewRecord(this, record, DataRowAction.Change, false, true); 
        } 

        ///  
        ///    
        ///       Sets the specified column's value to a null value.
        ///    
        ///  
        protected void SetNull(DataColumn column) {
            this[column] = DBNull.Value; 
        } 

        internal void SetNestedParentRow(DataRow parentRow, bool setNonNested) { 
            if (parentRow == null) {
                SetParentRowToDBNull();
                return;
            } 

            foreach (DataRelation relation in _table.ParentRelations) { 
                if (relation.Nested || setNonNested) { 
                    if (relation.ParentKey.Table == parentRow._table) {
                        object[] parentKeyValues = parentRow.GetKeyValues(relation.ParentKey); 
                        this.SetKeyValues(relation.ChildKey, parentKeyValues);

                        if (relation.Nested) {
                            if (parentRow._table == _table) 
                                this.CheckForLoops(relation);
                            else 
                                this.GetParentRow(relation); 
                        }
                    } 
                }
            }
        }
        ///  
        ///    [To be supplied.]
        ///  
        public void SetParentRow(DataRow parentRow) { 
            SetNestedParentRow(parentRow, true);
        } 

        /// 
        ///    
        ///       Sets current row's parent row with specified relation. 
        ///    
        ///  
        public void SetParentRow(DataRow parentRow, DataRelation relation) { 
            if (relation == null) {
                SetParentRow(parentRow); 
                return;
            }

            if (parentRow == null) { 
                SetParentRowToDBNull(relation);
                return; 
            } 

            //if (-1 == rowID) 
            //    throw ExceptionBuilder.ChildRowNotInTheTable();

            //if (-1 == parentRow.rowID)
            //    throw ExceptionBuilder.ParentRowNotInTheTable(); 

            if (_table.DataSet != parentRow._table.DataSet) 
                throw ExceptionBuilder.ParentRowNotInTheDataSet(); 

            if (relation.ChildKey.Table != _table) 
                throw ExceptionBuilder.SetParentRowTableMismatch(relation.ChildKey.Table.TableName, _table.TableName);

            if (relation.ParentKey.Table != parentRow._table)
                throw ExceptionBuilder.SetParentRowTableMismatch(relation.ParentKey.Table.TableName, parentRow._table.TableName); 

            object[] parentKeyValues = parentRow.GetKeyValues(relation.ParentKey); 
            this.SetKeyValues(relation.ChildKey, parentKeyValues); 
        }
 
        internal void SetParentRowToDBNull() {
            //if (-1 == rowID)
            //    throw ExceptionBuilder.ChildRowNotInTheTable();
 
            foreach (DataRelation relation in _table.ParentRelations)
                SetParentRowToDBNull(relation); 
        } 

        internal void SetParentRowToDBNull(DataRelation relation) { 
            Debug.Assert(relation != null, "The relation should not be null here.");

            //if (-1 == rowID)
            //    throw ExceptionBuilder.ChildRowNotInTheTable(); 

            if (relation.ChildKey.Table != _table) 
                throw ExceptionBuilder.SetParentRowTableMismatch(relation.ChildKey.Table.TableName, _table.TableName); 

 
            object[] parentKeyValues = new object[1];
            parentKeyValues[0] = DBNull.Value;
            this.SetKeyValues(relation.ChildKey, parentKeyValues);
        } 
        public void SetAdded(){
            if (this.RowState == DataRowState.Unchanged) { 
                _table.SetOldRecord(this, -1); 
            }
            else { 
                throw ExceptionBuilder.SetAddedAndModifiedCalledOnnonUnchanged();
            }
        }
 
        public void SetModified(){
            if (this.RowState == DataRowState.Unchanged) { 
                tempRecord = _table.NewRecord(newRecord); 
                if (tempRecord != -1) {
                    SetNewRecord(tempRecord); 
                }
            }
            else {
                throw ExceptionBuilder.SetAddedAndModifiedCalledOnnonUnchanged(); 
            }
        } 
 
/*
    RecordList contains the empty column storage needed. We need to copy the existing record values into this storage. 
*/
        internal int CopyValuesIntoStore(ArrayList storeList, ArrayList nullbitList, int storeIndex) {
            int recordCount = 0;
            if (oldRecord != -1) {//Copy original record for the row in Unchanged, Modified, Deleted state. 
                for (int i = 0; i < _columns.Count; i++) {
                    _columns[i].CopyValueIntoStore(oldRecord, storeList[i], (BitArray) nullbitList[i], storeIndex); 
                } 
                recordCount++;
                storeIndex++; 
            }

            DataRowState state = RowState;
            if ((DataRowState.Added == state) || (DataRowState.Modified == state)) { //Copy current record for the row in Added, Modified state. 
                for (int i = 0; i < _columns.Count; i++) {
                    _columns[i].CopyValueIntoStore(newRecord, storeList[i], (BitArray) nullbitList[i], storeIndex); 
                } 
                recordCount++;
                storeIndex++; 
            }

            if (-1 != tempRecord) {//Copy temp record for the row in edit mode.
                for (int i = 0; i < _columns.Count; i++) { 
                    _columns[i].CopyValueIntoStore(tempRecord, storeList[i], (BitArray)nullbitList[i], storeIndex);
                } 
                recordCount++; 
                storeIndex++;
            } 
            return recordCount;
        }
 		
        [Conditional("DEBUG")] 
        private void VerifyValueFromStorage(DataColumn column, DataRowVersion version, object valueFromStorage) {
            if (column.DataExpression != null && !inChangingEvent && tempRecord == -1) 
            { 
                // for unchanged rows, check current if original is asked for.
                // this is because by design, there is only single storage for an unchanged row. 
                if (version == DataRowVersion.Original && oldRecord == newRecord) {
                    version = DataRowVersion.Current;
                }
					 
                Debug.Assert(valueFromStorage.Equals(column.DataExpression.Evaluate(this, version)),
                    "Value from storage does lazily computed expression value"); 
            } 
        }
    } 

#if WINFSInternalOnly
    internal
#else 
    public
#endif 
    sealed class DataRowBuilder { 
        internal readonly DataTable   _table;
        internal int                  _record; 

        internal DataRowBuilder(DataTable table, int record) {
            _table = table;
            _record = record; 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK