private void SetNewRecordWorker(DataRow row, int proposedRecord, DataRowAction action, bool isInMerge, bool suppressEnsurePropertyChanged, int position, bool fireEvent, out Exception deferredException) { // this is the event workhorse... it will throw the changing/changed events // and update the indexes. Used by change, add, delete, revert. // order of execution is as follows // // 1) set temp record // 2) Check constraints for non-expression columns // 3) Raise RowChanging/RowDeleting with temp record // 4) set the new record in storage // 5) Update indexes with recordStateChanges - this will fire ListChanged & PropertyChanged events on associated views // 6) Evaluate all Expressions (exceptions are deferred)- this will fire ListChanged & PropertyChanged events on associated views // 7) Raise RowChanged/ RowDeleted // 8) Check constraints for expression columns Debug.Assert(row != null, "Row can't be null."); deferredException = null; if (row.tempRecord != proposedRecord) { // $HACK: for performance reasons, EndUpdate calls SetNewRecord with tempRecord == proposedRecord if (!inDataLoad) { row.CheckInTable(); CheckNotModifying(row); } if (proposedRecord == row.newRecord) { if (isInMerge) { Debug.Assert(fireEvent, "SetNewRecord is called with wrong parameter"); RaiseRowChanged(null, row, action); } return; } Debug.Assert(!row.inChangingEvent, "How can this row be in an infinite loop?"); row.tempRecord = proposedRecord; } DataRowChangeEventArgs drcevent = null; try { row._action = action; drcevent = RaiseRowChanging(null, row, action, fireEvent); } catch { row.tempRecord = -1; throw; } finally { row._action = DataRowAction.Nothing; } row.tempRecord = -1; int currentRecord = row.newRecord; // if we're deleting, then the oldRecord value will change, so need to track that if it's distinct from the newRecord. int secondRecord = (proposedRecord != -1 ? proposedRecord : (row.RowState != DataRowState.Unchanged ? row.oldRecord : -1)); if (action == DataRowAction.Add) { //if we come here from insert we do insert the row to collection if (position == -1) Rows.ArrayAdd(row); else Rows.ArrayInsert(row, position); } List<DataRow> cachedRows = null; if ((action == DataRowAction.Delete || action == DataRowAction.Change) && dependentColumns != null && dependentColumns.Count > 0) { // if there are expression columns, need to cache related rows for deletes and updates (key changes) // before indexes are modified. cachedRows = new List<DataRow>(); for (int j = 0; j < ParentRelations.Count; j++) { DataRelation relation = ParentRelations[j]; if (relation.ChildTable != row.Table) { continue; } cachedRows.InsertRange(cachedRows.Count, row.GetParentRows(relation)); } for (int j = 0; j < ChildRelations.Count; j++) { DataRelation relation = ChildRelations[j]; if (relation.ParentTable != row.Table) { continue; } cachedRows.InsertRange(cachedRows.Count, row.GetChildRows(relation)); } } // Dev10 Bug 688779: DataRowView.PropertyChanged are not raised on RejectChanges // if the newRecord is changing, the propertychanged event should be allowed to triggered for ListChangedType.Changed or .Moved // unless the specific condition is known that no data has changed, like DataRow.SetModified() if (!suppressEnsurePropertyChanged && !row.HasPropertyChanged && (row.newRecord != proposedRecord) && (-1 != proposedRecord) // explictly not fixing Dev10 Bug 692044: DataRowView.PropertyChanged are not raised on DataTable.Delete when mixing current and original records in RowStateFilter && (-1 != row.newRecord)) // explictly not fixing parts of Dev10 Bug 697909: when mixing current and original records in RowStateFilter { // DataRow will believe multiple edits occured and // DataView.ListChanged event w/ ListChangedType.ItemChanged will raise DataRowView.PropertyChanged event and // PropertyChangedEventArgs.PropertyName will now be empty string so // WPF will refresh the entire row row.LastChangedColumn = null; row.LastChangedColumn = null; } // Check whether we need to update indexes if (LiveIndexes.Count != 0) { // Dev10 bug #463087: DataTable internal index is currupted: '5' if ((-1 == currentRecord) && (-1 != proposedRecord) && (-1 != row.oldRecord) && (proposedRecord != row.oldRecord)) { // the transition from DataRowState.Deleted -> DataRowState.Modified // with same orginal record but new current record // needs to raise an ItemChanged or ItemMoved instead of ItemAdded in the ListChanged event. // for indexes/views listening for both DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent currentRecord = row.oldRecord; } DataViewRowState currentRecordStatePre = row.GetRecordState(currentRecord); DataViewRowState secondRecordStatePre = row.GetRecordState(secondRecord); row.newRecord = proposedRecord; if (proposedRecord != -1) this.recordManager[proposedRecord] = row; DataViewRowState currentRecordStatePost = row.GetRecordState(currentRecord); DataViewRowState secondRecordStatePost = row.GetRecordState(secondRecord); // may raise DataView.ListChanged event RecordStateChanged(currentRecord, currentRecordStatePre, currentRecordStatePost, secondRecord, secondRecordStatePre, secondRecordStatePost); } else { row.newRecord = proposedRecord; if (proposedRecord != -1) this.recordManager[proposedRecord] = row; } // Dev10 Bug 461199 - reset the last changed column here, after all // DataViews have raised their DataRowView.PropertyChanged event row.ResetLastChangedColumn(); // SQLBU 278737: Record manager corruption when reentrant write operations // free the 'currentRecord' only after all the indexes have been updated. // Corruption! { if (currentRecord != row.oldRecord) { FreeRecord(ref currentRecord); } } // RecordStateChanged raises ListChanged event at which time user may do work if (-1 != currentRecord) { if (currentRecord != row.oldRecord) { if ((currentRecord != row.tempRecord) && // Delete, AcceptChanges, BeginEdit (currentRecord != row.newRecord) && // RejectChanges & SetAdded (row == recordManager[currentRecord])) // AcceptChanges, NewRow { FreeRecord(ref currentRecord); } } } if (row.RowState == DataRowState.Detached && row.rowID != -1) { RemoveRow(row, false); } if (dependentColumns != null && dependentColumns.Count > 0) { try { EvaluateExpressions(row, action, cachedRows); } catch (Exception exc) { // For DataRows being added, throwing of exception from expression evaluation is // deferred until after the row has been completely added. if (action != DataRowAction.Add) { throw exc; } else { deferredException = exc; } } } try { if (fireEvent) { RaiseRowChanged(drcevent, row, action); } } catch (Exception e) { // if (!Common.ADP.IsCatchableExceptionType(e)) { throw; } ExceptionBuilder.TraceExceptionWithoutRethrow(e); // ignore the exception } }
// this is the event workhorse... it will throw the changing/changed events // and update the indexes. internal void SetOldRecord(DataRow row, int proposedRecord) { if (!inDataLoad) { row.CheckInTable(); CheckNotModifying(row); } if (proposedRecord == row.oldRecord) { return; } int originalRecord = row.oldRecord; // cache old record after potential RowChanging event try { // Check whether we need to update indexes if (LiveIndexes.Count != 0) { // Dev10 bug #463087: DataTable internal index is currupted: '5' if ((-1 == originalRecord) && (-1 != proposedRecord) && (-1 != row.newRecord) && (proposedRecord != row.newRecord)) { // the transition from DataRowState.Added -> DataRowState.Modified // with same current record but new original record // needs to raise an ItemChanged or ItemMoved instead of ItemAdded in the ListChanged event. // for indexes/views listening for both DataViewRowState.Added | DataViewRowState.ModifiedOriginal originalRecord = row.newRecord; } DataViewRowState originalRecordStatePre = row.GetRecordState(originalRecord); DataViewRowState proposedRecordStatePre = row.GetRecordState(proposedRecord); row.oldRecord = proposedRecord; if (proposedRecord != -1) this.recordManager[proposedRecord] = row; DataViewRowState originalRecordStatePost = row.GetRecordState(originalRecord); DataViewRowState proposedRecordStatePost = row.GetRecordState(proposedRecord); RecordStateChanged(originalRecord, originalRecordStatePre, originalRecordStatePost, proposedRecord, proposedRecordStatePre, proposedRecordStatePost); } else { row.oldRecord = proposedRecord; if (proposedRecord != -1) this.recordManager[proposedRecord] = row; } } finally { if ((originalRecord != -1) && (originalRecord != row.tempRecord) && (originalRecord != row.oldRecord) && (originalRecord != row.newRecord)) { FreeRecord(ref originalRecord); } // else during an event 'row.AcceptChanges(); row.BeginEdit(); row.EndEdit();' if (row.RowState == DataRowState.Detached && row.rowID != -1) { RemoveRow(row, false); } } }
// InsertRecordToIndexes inserts the given record (using row and version) to all indexes and it stores and returns the position of inserted // record to each index // IT SHOULD NOT CAUSE ANY EVENT TO BE FIRED internal int[] InsertRecordToIndexes(DataRow row, DataRowVersion version) { int indexCount = LiveIndexes.Count; int [] positionIndexes = new int[indexCount]; int recordNo = row.GetRecordFromVersion(version); DataViewRowState states = row.GetRecordState(recordNo); while (--indexCount >= 0) { if (row.HasVersion(version)) { if ((states & indexes[indexCount].RecordStates) != DataViewRowState.None) { positionIndexes [indexCount] = indexes[indexCount].InsertRecordToIndex(recordNo); } else { positionIndexes [indexCount] = -1; } } } return positionIndexes; }
internal void RemoveRow(DataRow row, bool check) { if (row.rowID == -1) { throw ExceptionBuilder.RowAlreadyRemoved(); } if (check && dataSet != null) { for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) { constraints.GetForeignKeyConstraint().CheckCanRemoveParentRow(row); } } int oldRecord = row.oldRecord; int newRecord = row.newRecord; DataViewRowState oldRecordStatePre = row.GetRecordState(oldRecord); DataViewRowState newRecordStatePre = row.GetRecordState(newRecord); row.oldRecord = -1; row.newRecord = -1; if (oldRecord == newRecord) { oldRecord = -1; } RecordStateChanged(oldRecord, oldRecordStatePre, DataViewRowState.None, newRecord, newRecordStatePre, DataViewRowState.None); FreeRecord(ref oldRecord); FreeRecord(ref newRecord); row.rowID = -1; Rows.ArrayRemove(row); }
internal void InsertRow(DataRow row, long proposedID) { IntPtr hscp; Bid.ScopeEnter(out hscp, "<ds.DataTable.InsertRow|INFO> %d#, row=%d\n", ObjectID, row.ObjectID); try { if (row.Table != this) { throw ExceptionBuilder.RowAlreadyInOtherCollection(); } if (row.rowID != -1) { throw ExceptionBuilder.RowAlreadyInTheCollection(); } if (row.oldRecord == -1 && row.newRecord == -1) { throw ExceptionBuilder.RowEmpty(); } if (proposedID == -1) proposedID = nextRowID; row.rowID = proposedID; if (nextRowID <= proposedID) nextRowID = checked(proposedID + 1); DataRowChangeEventArgs drcevent = null; if (row.newRecord != -1) { row.tempRecord = row.newRecord; row.newRecord = -1; try { drcevent = RaiseRowChanging(null, row, DataRowAction.Add, true); } catch { row.tempRecord = -1; throw; } row.newRecord = row.tempRecord; row.tempRecord = -1; } if (row.oldRecord != -1) recordManager[row.oldRecord] = row; if (row.newRecord != -1) recordManager[row.newRecord] = row; Rows.ArrayAdd(row); // SQL BU Defect Tracking 247738, 323482 row should be in the // collection when maintaining the indexes if (row.RowState == DataRowState.Unchanged){ // how about row.oldRecord == row.newRecord both == -1 RecordStateChanged(row.oldRecord, DataViewRowState.None, DataViewRowState.Unchanged); } else { RecordStateChanged(row.oldRecord, DataViewRowState.None, row.GetRecordState(row.oldRecord), row.newRecord, DataViewRowState.None, row.GetRecordState(row.newRecord)); } if (dependentColumns != null && dependentColumns.Count > 0) EvaluateExpressions(row, DataRowAction.Add, null); RaiseRowChanged(drcevent, row, DataRowAction.Add); } finally { Bid.ScopeLeave(ref hscp); } }
// RemoveRecordFromIndexes removes the given record (using row and version) from all indexes and it stores and returns the position of deleted // record from each index // IT SHOULD NOT CAUSE ANY EVENT TO BE FIRED internal int[] RemoveRecordFromIndexes(DataRow row, DataRowVersion version) { int indexCount = LiveIndexes.Count; int [] positionIndexes = new int[indexCount]; int recordNo = row.GetRecordFromVersion(version); DataViewRowState states = row.GetRecordState(recordNo); while (--indexCount >= 0) { if (row.HasVersion(version) && ((states & indexes[indexCount].RecordStates) != DataViewRowState.None)) { int index = indexes[indexCount].GetIndex(recordNo); if (index > -1) { positionIndexes [indexCount] = index; indexes[indexCount].DeleteRecordFromIndex(index); // this will delete the record from index and MUSt not fire event } else { positionIndexes [indexCount] = -1; // this means record was not in index } } else { positionIndexes [indexCount] = -1; // this means record was not in index } } return positionIndexes; }
internal void SetOldRecord(DataRow row, int proposedRecord) { if (!this.inDataLoad) { row.CheckInTable(); this.CheckNotModifying(row); } if (proposedRecord != row.oldRecord) { int oldRecord = row.oldRecord; try { if (this.LiveIndexes.Count != 0) { if (((-1 == oldRecord) && (-1 != proposedRecord)) && ((-1 != row.newRecord) && (proposedRecord != row.newRecord))) { oldRecord = row.newRecord; } DataViewRowState recordState = row.GetRecordState(oldRecord); DataViewRowState state3 = row.GetRecordState(proposedRecord); row.oldRecord = proposedRecord; if (proposedRecord != -1) { this.recordManager[proposedRecord] = row; } DataViewRowState state2 = row.GetRecordState(oldRecord); DataViewRowState state = row.GetRecordState(proposedRecord); this.RecordStateChanged(oldRecord, recordState, state2, proposedRecord, state3, state); } else { row.oldRecord = proposedRecord; if (proposedRecord != -1) { this.recordManager[proposedRecord] = row; } } } finally { if (((oldRecord != -1) && (oldRecord != row.tempRecord)) && ((oldRecord != row.oldRecord) && (oldRecord != row.newRecord))) { this.FreeRecord(ref oldRecord); } if ((row.RowState == DataRowState.Detached) && (row.rowID != -1L)) { this.RemoveRow(row, false); } } } }
internal void InsertRow(DataRow row, long proposedID) { long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataTable.InsertRow|INFO> {0}, row={1}", ObjectID, row._objectID); try { if (row.Table != this) { throw ExceptionBuilder.RowAlreadyInOtherCollection(); } if (row.rowID != -1) { throw ExceptionBuilder.RowAlreadyInTheCollection(); } if (row._oldRecord == -1 && row._newRecord == -1) { throw ExceptionBuilder.RowEmpty(); } if (proposedID == -1) { proposedID = _nextRowID; } row.rowID = proposedID; if (_nextRowID <= proposedID) { _nextRowID = checked(proposedID + 1); } DataRowChangeEventArgs drcevent = null; if (row._newRecord != -1) { row._tempRecord = row._newRecord; row._newRecord = -1; try { drcevent = RaiseRowChanging(null, row, DataRowAction.Add, true); } catch { row._tempRecord = -1; throw; } row._newRecord = row._tempRecord; row._tempRecord = -1; } if (row._oldRecord != -1) { _recordManager[row._oldRecord] = row; } if (row._newRecord != -1) { _recordManager[row._newRecord] = row; } Rows.ArrayAdd(row); if (row.RowState == DataRowState.Unchanged) { // how about row.oldRecord == row.newRecord both == -1 RecordStateChanged(row._oldRecord, DataViewRowState.None, DataViewRowState.Unchanged); } else { RecordStateChanged(row._oldRecord, DataViewRowState.None, row.GetRecordState(row._oldRecord), row._newRecord, DataViewRowState.None, row.GetRecordState(row._newRecord)); } if (_dependentColumns != null && _dependentColumns.Count > 0) { EvaluateExpressions(row, DataRowAction.Add, null); } RaiseRowChanged(drcevent, row, DataRowAction.Add); } finally { DataCommonEventSource.Log.ExitScope(logScopeId); } }
private void SetNewRecordWorker(DataRow row, int proposedRecord, DataRowAction action, bool isInMerge, bool suppressEnsurePropertyChanged, int position, bool fireEvent, out Exception deferredException) { deferredException = null; if (row.tempRecord != proposedRecord) { if (!this.inDataLoad) { row.CheckInTable(); this.CheckNotModifying(row); } if (proposedRecord == row.newRecord) { if (isInMerge) { this.RaiseRowChanged(null, row, action); } return; } row.tempRecord = proposedRecord; } DataRowChangeEventArgs args = null; try { row._action = action; args = this.RaiseRowChanging(null, row, action, fireEvent); } catch { row.tempRecord = -1; throw; } finally { row._action = DataRowAction.Nothing; } row.tempRecord = -1; int newRecord = row.newRecord; int record = (proposedRecord != -1) ? proposedRecord : ((row.RowState != DataRowState.Unchanged) ? row.oldRecord : -1); if (action == DataRowAction.Add) { if (position == -1) { this.Rows.ArrayAdd(row); } else { this.Rows.ArrayInsert(row, position); } } List<DataRow> cachedRows = null; if (((action == DataRowAction.Delete) || (action == DataRowAction.Change)) && ((this.dependentColumns != null) && (this.dependentColumns.Count > 0))) { cachedRows = new List<DataRow>(); for (int i = 0; i < this.ParentRelations.Count; i++) { DataRelation relation2 = this.ParentRelations[i]; if (relation2.ChildTable == row.Table) { cachedRows.InsertRange(cachedRows.Count, row.GetParentRows(relation2)); } } for (int j = 0; j < this.ChildRelations.Count; j++) { DataRelation relation = this.ChildRelations[j]; if (relation.ParentTable == row.Table) { cachedRows.InsertRange(cachedRows.Count, row.GetChildRows(relation)); } } } if (((!suppressEnsurePropertyChanged && !row.HasPropertyChanged) && ((row.newRecord != proposedRecord) && (-1 != proposedRecord))) && (-1 != row.newRecord)) { row.LastChangedColumn = null; row.LastChangedColumn = null; } if (this.LiveIndexes.Count != 0) { if (((-1 == newRecord) && (-1 != proposedRecord)) && ((-1 != row.oldRecord) && (proposedRecord != row.oldRecord))) { newRecord = row.oldRecord; } DataViewRowState recordState = row.GetRecordState(newRecord); DataViewRowState state3 = row.GetRecordState(record); row.newRecord = proposedRecord; if (proposedRecord != -1) { this.recordManager[proposedRecord] = row; } DataViewRowState state2 = row.GetRecordState(newRecord); DataViewRowState state = row.GetRecordState(record); this.RecordStateChanged(newRecord, recordState, state2, record, state3, state); } else { row.newRecord = proposedRecord; if (proposedRecord != -1) { this.recordManager[proposedRecord] = row; } } row.ResetLastChangedColumn(); if ((((-1 != newRecord) && (newRecord != row.oldRecord)) && ((newRecord != row.tempRecord) && (newRecord != row.newRecord))) && (row == this.recordManager[newRecord])) { this.FreeRecord(ref newRecord); } if ((row.RowState == DataRowState.Detached) && (row.rowID != -1L)) { this.RemoveRow(row, false); } if ((this.dependentColumns != null) && (this.dependentColumns.Count > 0)) { try { this.EvaluateExpressions(row, action, cachedRows); } catch (Exception exception2) { if (action != DataRowAction.Add) { throw exception2; } deferredException = exception2; } } try { if (fireEvent) { this.RaiseRowChanged(args, row, action); } } catch (Exception exception) { if (!ADP.IsCatchableExceptionType(exception)) { throw; } ExceptionBuilder.TraceExceptionWithoutRethrow(exception); } }
internal void RemoveRow(DataRow row, bool check) { if (row.rowID == -1L) { throw ExceptionBuilder.RowAlreadyRemoved(); } if (check && (this.dataSet != null)) { ParentForeignKeyConstraintEnumerator enumerator = new ParentForeignKeyConstraintEnumerator(this.dataSet, this); while (enumerator.GetNext()) { enumerator.GetForeignKeyConstraint().CheckCanRemoveParentRow(row); } } int oldRecord = row.oldRecord; int newRecord = row.newRecord; DataViewRowState recordState = row.GetRecordState(oldRecord); DataViewRowState state = row.GetRecordState(newRecord); row.oldRecord = -1; row.newRecord = -1; if (oldRecord == newRecord) { oldRecord = -1; } this.RecordStateChanged(oldRecord, recordState, DataViewRowState.None, newRecord, state, DataViewRowState.None); this.FreeRecord(ref oldRecord); this.FreeRecord(ref newRecord); row.rowID = -1L; this.Rows.ArrayRemove(row); }
internal int[] RemoveRecordFromIndexes(DataRow row, DataRowVersion version) { int count = this.LiveIndexes.Count; int[] numArray = new int[count]; int recordFromVersion = row.GetRecordFromVersion(version); DataViewRowState recordState = row.GetRecordState(recordFromVersion); while (--count >= 0) { if (row.HasVersion(version) && ((recordState & this.indexes[count].RecordStates) != DataViewRowState.None)) { int index = this.indexes[count].GetIndex(recordFromVersion); if (index > -1) { numArray[count] = index; this.indexes[count].DeleteRecordFromIndex(index); } else { numArray[count] = -1; } } else { numArray[count] = -1; } } return numArray; }
internal void InsertRow(DataRow row, long proposedID) { IntPtr ptr; Bid.ScopeEnter(out ptr, "<ds.DataTable.InsertRow|INFO> %d#, row=%d\n", this.ObjectID, row.ObjectID); try { if (row.Table != this) { throw ExceptionBuilder.RowAlreadyInOtherCollection(); } if (row.rowID != -1L) { throw ExceptionBuilder.RowAlreadyInTheCollection(); } if ((row.oldRecord == -1) && (row.newRecord == -1)) { throw ExceptionBuilder.RowEmpty(); } if (proposedID == -1L) { proposedID = this.nextRowID; } row.rowID = proposedID; if (this.nextRowID <= proposedID) { this.nextRowID = proposedID + 1L; } DataRowChangeEventArgs args = null; if (row.newRecord != -1) { row.tempRecord = row.newRecord; row.newRecord = -1; try { args = this.RaiseRowChanging(null, row, DataRowAction.Add, true); } catch { row.tempRecord = -1; throw; } row.newRecord = row.tempRecord; row.tempRecord = -1; } if (row.oldRecord != -1) { this.recordManager[row.oldRecord] = row; } if (row.newRecord != -1) { this.recordManager[row.newRecord] = row; } this.Rows.ArrayAdd(row); if (row.RowState == DataRowState.Unchanged) { this.RecordStateChanged(row.oldRecord, DataViewRowState.None, DataViewRowState.Unchanged); } else { this.RecordStateChanged(row.oldRecord, DataViewRowState.None, row.GetRecordState(row.oldRecord), row.newRecord, DataViewRowState.None, row.GetRecordState(row.newRecord)); } if ((this.dependentColumns != null) && (this.dependentColumns.Count > 0)) { this.EvaluateExpressions(row, DataRowAction.Add, null); } this.RaiseRowChanged(args, row, DataRowAction.Add); } finally { Bid.ScopeLeave(ref ptr); } }
internal int[] InsertRecordToIndexes(DataRow row, DataRowVersion version) { int count = this.LiveIndexes.Count; int[] numArray = new int[count]; int recordFromVersion = row.GetRecordFromVersion(version); DataViewRowState recordState = row.GetRecordState(recordFromVersion); while (--count >= 0) { if (row.HasVersion(version)) { if ((recordState & this.indexes[count].RecordStates) != DataViewRowState.None) { numArray[count] = this.indexes[count].InsertRecordToIndex(recordFromVersion); } else { numArray[count] = -1; } } } return numArray; }