// 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); } } }
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); } } } }
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 } }
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); } }