public GetParentRows ( |
||
relation | ||
return | System.Data.DataRow[] |
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 } }
internal void EvaluateDependentExpressions(List<DataColumn> columns, DataRow row, DataRowVersion version, List<DataRow> cachedRows) { if (columns == null) return; //Expression evaluation is done first over same table expressions. int count = columns.Count; for(int i = 0; i < count; i++) { if (columns[i].Table == this) {// if this column is in my table DataColumn dc = columns[i]; if (dc.DataExpression != null && dc.DataExpression.HasLocalAggregate()) { // if column expression references a local Table aggregate we need to recalc it for the each row in the local table DataRowVersion expressionVersion = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version; bool isConst = dc.DataExpression.IsTableAggregate(); //is expression constant for entire table? object newValue = null; if (isConst) { //if new value, just compute once newValue = dc.DataExpression.Evaluate(row, expressionVersion); } for (int j = 0; j < Rows.Count; j++) { //evaluate for all rows in the table DataRow dr = Rows[j]; if (dr.RowState == DataRowState.Deleted) { continue; } else if (expressionVersion == DataRowVersion.Original && (dr.oldRecord == -1 || dr.oldRecord == dr.newRecord)) { continue; } if (!isConst) { newValue = dc.DataExpression.Evaluate(dr, expressionVersion); } SilentlySetValue(dr, dc, expressionVersion, newValue); } } else { if (row.RowState == DataRowState.Deleted) { continue; } else if (version == DataRowVersion.Original && (row.oldRecord == -1 || row.oldRecord == row.newRecord)) { continue; } SilentlySetValue(row, dc, version, dc.DataExpression == null ? dc.DefaultValue : dc.DataExpression.Evaluate(row, version)); } } } // now do expression evaluation for expression columns other tables. count = columns.Count; for(int i = 0; i < count; i++) { DataColumn dc = columns[i]; // if this column is NOT in my table or it is in the table and is not a local aggregate (self refs) if (dc.Table != this || (dc.DataExpression != null && !dc.DataExpression.HasLocalAggregate())) { DataRowVersion foreignVer = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version; // first - evaluate expressions for cachedRows (deletes & updates) if (cachedRows != null) { foreach (DataRow cachedRow in cachedRows) { if (cachedRow.Table != dc.Table) continue; // don't update original version if child row doesn't have an oldRecord. if (foreignVer == DataRowVersion.Original && cachedRow.newRecord == cachedRow.oldRecord) continue; if (cachedRow != null && ((cachedRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || cachedRow.oldRecord != -1))) {// if deleted GetRecordFromVersion will throw object newValue = dc.DataExpression.Evaluate(cachedRow, foreignVer); SilentlySetValue(cachedRow, dc, foreignVer, newValue); } } } // next check parent relations for (int j = 0; j < ParentRelations.Count; j++) { DataRelation relation = ParentRelations[j]; if (relation.ParentTable != dc.Table) continue; foreach (DataRow parentRow in row.GetParentRows(relation, version)) { if (cachedRows != null && cachedRows.Contains(parentRow)) continue; // don't update original version if child row doesn't have an oldRecord. if (foreignVer == DataRowVersion.Original && parentRow.newRecord == parentRow.oldRecord) continue; if (parentRow != null && ((parentRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || parentRow.oldRecord != -1))) {// if deleted GetRecordFromVersion will throw object newValue = dc.DataExpression.Evaluate(parentRow, foreignVer); SilentlySetValue(parentRow, dc, foreignVer, newValue); } } } // next check child relations for (int j = 0; j < ChildRelations.Count; j++) { DataRelation relation = ChildRelations[j]; if (relation.ChildTable != dc.Table) continue; foreach (DataRow childRow in row.GetChildRows(relation, version)) { // don't update original version if child row doesn't have an oldRecord. if (cachedRows != null && cachedRows.Contains(childRow)) continue; if (foreignVer == DataRowVersion.Original && childRow.newRecord == childRow.oldRecord) continue; if (childRow != null && ((childRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || childRow.oldRecord != -1))) { // if deleted GetRecordFromVersion will throw object newValue = dc.DataExpression.Evaluate(childRow, foreignVer); SilentlySetValue(childRow, dc, foreignVer, newValue); } } } } } }
private void MarkRelatedRowsAsModified(TableChanges[] bitMatrix, DataRow row) { DataRelationCollection parentRelations = row.Table.ParentRelations; int count = parentRelations.Count; for (int i = 0; i < count; i++) { foreach (DataRow row2 in row.GetParentRows(parentRelations[i], DataRowVersion.Current)) { int index = this.Tables.IndexOf(row2.Table); int num3 = row2.Table.Rows.IndexOf(row2); if (!bitMatrix[index][num3]) { bitMatrix[index][num3] = true; if (DataRowState.Deleted != row2.RowState) { this.MarkRelatedRowsAsModified(bitMatrix, row2); } } } } }
public DataRow[] GetReferencedRows (DataRow row) { // Verify the column reference is valid GetColumn (row); switch (refTable) { case ReferencedTable.Self: default: DataRow[] rows = row.Table.NewRowArray(row.Table.Rows.Count); row.Table.Rows.CopyTo (rows, 0); return rows; case ReferencedTable.Parent: return row.GetParentRows (GetRelation (row)); case ReferencedTable.Child: return row.GetChildRows (GetRelation (row)); } }
private static bool parentsExists(DataRow row) { if (row.Table.ParentRelations.Count == 0) return true; foreach (DataRelation rel in row.Table.ParentRelations) return row.GetParentRows(rel).Length > 0; return false; }
private void MarkRelatedRowsAsModified(TableChanges[] bitMatrix, DataRow row) { DataRelationCollection relations = row.Table.ParentRelations; int relationCount = relations.Count; for (int relatedIndex = 0; relatedIndex < relationCount; ++relatedIndex) { DataRow[] relatedRows = row.GetParentRows(relations[relatedIndex], DataRowVersion.Current); foreach (DataRow relatedRow in relatedRows) { int relatedTableIndex = this.Tables.IndexOf(relatedRow.Table); int relatedRowIndex = relatedRow.Table.Rows.IndexOf(relatedRow); if (!bitMatrix[relatedTableIndex][relatedRowIndex]) { bitMatrix[relatedTableIndex][relatedRowIndex] = true; if (DataRowState.Deleted != relatedRow.RowState) { // recurse into related rows MarkRelatedRowsAsModified(bitMatrix, relatedRow); } } } } }
public void ParentRowTest2 () { DataSet ds = new DataSet (); DataTable tableP = ds.Tables.Add ("Parent"); DataTable tableC = ds.Tables.Add ("Child"); DataColumn colC; DataRow rowC; colC = new DataColumn (); colC.DataType = Type.GetType ("System.Int32"); colC.ColumnName = "Id"; colC.AutoIncrement = true; tableP.Columns.Add (colC); colC = new DataColumn (); colC.DataType = Type.GetType ("System.Int32"); colC.ColumnName = "Id"; tableC.Columns.Add (colC); row = tableP.Rows.Add (new object [0]); rowC = tableC.NewRow (); ds.EnforceConstraints = false; DataRelation dr = new DataRelation ("PO", tableP.Columns ["Id"], tableC.Columns ["Id"]); ds.Relations.Add (dr); rowC.SetParentRow (row, dr); DataRow [] rows = rowC.GetParentRows (dr); AssertEquals ("#A49", 1, rows.Length); AssertEquals ("#A50", tableP.Rows [0], rows [0]); try{ rows = row.GetParentRows (dr); }catch(InvalidConstraintException){ //Test done return ; }catch(Exception e){ Fail("#A51, InvalidConstraintException expected, got : " + e); } Fail("#A52, InvalidConstraintException expected but got none."); }
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 EvaluateDependentExpressions(List<DataColumn> columns, DataRow row, DataRowVersion version, List<DataRow> cachedRows) { if (columns != null) { int count = columns.Count; for (int i = 0; i < count; i++) { if (columns[i].Table == this) { DataColumn dc = columns[i]; if ((dc.DataExpression != null) && dc.DataExpression.HasLocalAggregate()) { DataRowVersion version3 = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version; bool flag = dc.DataExpression.IsTableAggregate(); object newValue = null; if (flag) { newValue = dc.DataExpression.Evaluate(row, version3); } for (int k = 0; k < this.Rows.Count; k++) { DataRow row5 = this.Rows[k]; if ((row5.RowState != DataRowState.Deleted) && ((version3 != DataRowVersion.Original) || ((row5.oldRecord != -1) && (row5.oldRecord != row5.newRecord)))) { if (!flag) { newValue = dc.DataExpression.Evaluate(row5, version3); } this.SilentlySetValue(row5, dc, version3, newValue); } } } else if ((row.RowState != DataRowState.Deleted) && ((version != DataRowVersion.Original) || ((row.oldRecord != -1) && (row.oldRecord != row.newRecord)))) { this.SilentlySetValue(row, dc, version, (dc.DataExpression == null) ? dc.DefaultValue : dc.DataExpression.Evaluate(row, version)); } } } count = columns.Count; for (int j = 0; j < count; j++) { DataColumn column = columns[j]; if ((column.Table != this) || ((column.DataExpression != null) && !column.DataExpression.HasLocalAggregate())) { DataRowVersion version2 = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version; if (cachedRows != null) { foreach (DataRow row4 in cachedRows) { if (((row4.Table == column.Table) && ((version2 != DataRowVersion.Original) || (row4.newRecord != row4.oldRecord))) && (((row4 != null) && (row4.RowState != DataRowState.Deleted)) && ((version != DataRowVersion.Original) || (row4.oldRecord != -1)))) { object obj5 = column.DataExpression.Evaluate(row4, version2); this.SilentlySetValue(row4, column, version2, obj5); } } } for (int m = 0; m < this.ParentRelations.Count; m++) { DataRelation relation2 = this.ParentRelations[m]; if (relation2.ParentTable == column.Table) { foreach (DataRow row3 in row.GetParentRows(relation2, version)) { if ((((cachedRows == null) || !cachedRows.Contains(row3)) && ((version2 != DataRowVersion.Original) || (row3.newRecord != row3.oldRecord))) && (((row3 != null) && (row3.RowState != DataRowState.Deleted)) && ((version != DataRowVersion.Original) || (row3.oldRecord != -1)))) { object obj4 = column.DataExpression.Evaluate(row3, version2); this.SilentlySetValue(row3, column, version2, obj4); } } } } for (int n = 0; n < this.ChildRelations.Count; n++) { DataRelation relation = this.ChildRelations[n]; if (relation.ChildTable == column.Table) { foreach (DataRow row2 in row.GetChildRows(relation, version)) { if ((((cachedRows == null) || !cachedRows.Contains(row2)) && ((version2 != DataRowVersion.Original) || (row2.newRecord != row2.oldRecord))) && (((row2 != null) && (row2.RowState != DataRowState.Deleted)) && ((version != DataRowVersion.Original) || (row2.oldRecord != -1)))) { object obj3 = column.DataExpression.Evaluate(row2, version2); this.SilentlySetValue(row2, column, version2, obj3); } } } } } } } }