Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Data / System / Data / ForeignKeyConstraint.cs / 1 / ForeignKeyConstraint.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data { using System; using System.ComponentModel; using System.Diagnostics; using System.Data.Common; ////// [ DefaultProperty("ConstraintName"), Editor("Microsoft.VSDesigner.Data.Design.ForeignKeyConstraintEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing), ] #if WINFSInternalOnly internal #else public #endif class ForeignKeyConstraint : Constraint { // constants internal const Rule Rule_Default = Rule.Cascade; internal const AcceptRejectRule AcceptRejectRule_Default = AcceptRejectRule.None; // properties internal Rule deleteRule = Rule_Default; internal Rule updateRule = Rule_Default; internal AcceptRejectRule acceptRejectRule = AcceptRejectRule_Default; private DataKey childKey; private DataKey parentKey; // Design time serialization internal string constraintName = null; internal string[] parentColumnNames = null; internal string[] childColumnNames = null; internal string parentTableName = null; internal string parentTableNamespace = null; ///Represents an action /// restriction enforced on a set of columns in a primary key/foreign key relationship when /// a value or row is either deleted or updated. ////// public ForeignKeyConstraint(DataColumn parentColumn, DataColumn childColumn) : this(null, parentColumn, childColumn) { } ////// Initializes a new instance of the ///class with the specified parent and /// child objects. /// /// public ForeignKeyConstraint(string constraintName, DataColumn parentColumn, DataColumn childColumn) { DataColumn[] parentColumns = new DataColumn[] {parentColumn}; DataColumn[] childColumns = new DataColumn[] {childColumn}; Create(constraintName, parentColumns, childColumns); } ////// Initializes a new instance of the ///class with the specified name, /// parent and child objects. /// /// public ForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) : this(null, parentColumns, childColumns) { } ////// Initializes a new instance of the ///class with the specified arrays /// of parent and child objects. /// /// public ForeignKeyConstraint(string constraintName, DataColumn[] parentColumns, DataColumn[] childColumns) { Create(constraintName, parentColumns, childColumns); } // construct design time object ////// Initializes a new instance of the ///class with the specified name, /// and arrays of parent and child objects. /// /// [Browsable(false)] public ForeignKeyConstraint(string constraintName, string parentTableName, string[] parentColumnNames, string[] childColumnNames, AcceptRejectRule acceptRejectRule, Rule deleteRule, Rule updateRule) { this.constraintName = constraintName; this.parentColumnNames = parentColumnNames; this.childColumnNames = childColumnNames; this.parentTableName = parentTableName; this.acceptRejectRule = acceptRejectRule; this.deleteRule = deleteRule; this.updateRule = updateRule; // ForeignKeyConstraint(constraintName, parentTableName, null, parentColumnNames, childColumnNames,acceptRejectRule, deleteRule, updateRule) } // construct design time object [Browsable(false)] public ForeignKeyConstraint(string constraintName, string parentTableName, string parentTableNamespace, string[] parentColumnNames, string[] childColumnNames, AcceptRejectRule acceptRejectRule, Rule deleteRule, Rule updateRule) { this.constraintName = constraintName; this.parentColumnNames = parentColumnNames; this.childColumnNames = childColumnNames; this.parentTableName = parentTableName; this.parentTableNamespace= parentTableNamespace; this.acceptRejectRule = acceptRejectRule; this.deleteRule = deleteRule; this.updateRule = updateRule; } ///[To be supplied.] ////// The internal constraint object for the child table. /// internal DataKey ChildKey { get { CheckStateForProperty(); return childKey; } } ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ForeignKeyConstraintChildColumnsDescr), ReadOnly(true) ] public virtual DataColumn[] Columns { get { CheckStateForProperty(); return childKey.ToArray(); } } ////// Gets the child columns of this constraint. /// ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ConstraintTableDescr), ReadOnly(true) ] public override DataTable Table { get { CheckStateForProperty(); return childKey.Table; } } internal string[] ParentColumnNames { get { return parentKey.GetColumnNames(); } } internal string[] ChildColumnNames { get { return childKey.GetColumnNames(); } } internal override void CheckCanAddToCollection(ConstraintCollection constraints) { if (Table != constraints.Table) throw ExceptionBuilder.ConstraintAddFailed(constraints.Table); if (Table.Locale.LCID != RelatedTable.Locale.LCID || Table.CaseSensitive != RelatedTable.CaseSensitive) throw ExceptionBuilder.CaseLocaleMismatch(); } internal override bool CanBeRemovedFromCollection(ConstraintCollection constraints, bool fThrowException) { return true; } internal bool IsKeyNull( object[] values ) { for (int i = 0; i < values.Length; i++) { if (! DataStorage.IsObjectNull(values[i])) return false; } return true; } internal override bool IsConstraintViolated() { Index childIndex = childKey.GetSortIndex(); object[] uniqueChildKeys = childIndex.GetUniqueKeyValues(); bool errors = false; Index parentIndex = parentKey.GetSortIndex(); for (int i = 0; i < uniqueChildKeys.Length; i++) { object[] childValues = (object[]) uniqueChildKeys[i]; if (!IsKeyNull(childValues)) { if (!parentIndex.IsKeyInIndex(childValues)) { DataRow[] rows = childIndex.GetRows(childIndex.FindRecords(childValues)); string error = Res.GetString(Res.DataConstraint_ForeignKeyViolation, ConstraintName, ExceptionBuilder.KeysToString(childValues)); for (int j = 0; j < rows.Length; j++) { rows[j].RowError = error; } errors = true; } } } return errors; } internal override bool CanEnableConstraint() { if (Table.DataSet == null || !Table.DataSet.EnforceConstraints) return true; Index childIndex = childKey.GetSortIndex(); object[] uniqueChildKeys = childIndex.GetUniqueKeyValues(); Index parentIndex = parentKey.GetSortIndex(); for (int i = 0; i < uniqueChildKeys.Length; i++) { object[] childValues = (object[]) uniqueChildKeys[i]; if (!IsKeyNull(childValues) && !parentIndex.IsKeyInIndex(childValues)) { return false; } } return true; } internal void CascadeCommit(DataRow row) { if (row.RowState == DataRowState.Detached) return; if (acceptRejectRule == AcceptRejectRule.Cascade) { Index childIndex = childKey.GetSortIndex( row.RowState == DataRowState.Deleted ? DataViewRowState.Deleted : DataViewRowState.CurrentRows ); object[] key = row.GetKeyValues(parentKey, row.RowState == DataRowState.Deleted ? DataRowVersion.Original : DataRowVersion.Default ); if (IsKeyNull(key)) { return; } Range range = childIndex.FindRecords(key); if (!range.IsNull) { // SQLBU 499726 - DataTable internal index is corrupted: '13' // Self-referencing table has suspendIndexEvents, in the multi-table scenario the child table hasn't // this allows the self-ref table to maintain the index while in the child-table doesn't DataRow[] rows = childIndex.GetRows(range); foreach(DataRow childRow in rows) { if (DataRowState.Detached != childRow.RowState) { if (childRow.inCascade) continue; childRow.AcceptChanges(); } } } } } internal void CascadeDelete(DataRow row) { if (-1 == row.newRecord) return; object[] currentKey = row.GetKeyValues(parentKey, DataRowVersion.Current); if (IsKeyNull(currentKey)) { return; } Index childIndex = childKey.GetSortIndex(); switch (DeleteRule) { case Rule.None: { if (row.Table.DataSet.EnforceConstraints) { // if we're not cascading deletes, we should throw if we're going to strand a child row under enforceConstraints. Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { if (range.Count == 1 && childIndex.GetRow(range.Min) == row) return; throw ExceptionBuilder.FailedCascadeDelete(ConstraintName); } } break; } case Rule.Cascade: { object[] key = row.GetKeyValues(parentKey, DataRowVersion.Default); Range range = childIndex.FindRecords(key); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { DataRow r = rows[j]; if (r.inCascade) continue; r.Table.DeleteRow(r); } } break; } case Rule.SetNull: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = DBNull.Value; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; if (row != rows[j]) rows[j].SetKeyValues(childKey, proposedKey); } } break; } case Rule.SetDefault: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = childKey.ColumnsReference[i].DefaultValue; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; if (row != rows[j]) rows[j].SetKeyValues(childKey, proposedKey); } } break; } default: { Debug.Assert(false, "Unknown Rule value"); break; } } } internal void CascadeRollback(DataRow row) { Index childIndex = childKey.GetSortIndex( row.RowState == DataRowState.Deleted ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows); object[] key = row.GetKeyValues(parentKey, row.RowState == DataRowState.Modified ? DataRowVersion.Current : DataRowVersion.Default ); // Bug : This is definitely not a proper fix. (Ref. MDAC Bug 73592) if (IsKeyNull(key)) { return; } Range range = childIndex.FindRecords(key); if (acceptRejectRule == AcceptRejectRule.Cascade) { if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { if (rows[j].inCascade) continue; rows[j].RejectChanges(); } } } else { // AcceptRejectRule.None if (row.RowState != DataRowState.Deleted && row.Table.DataSet.EnforceConstraints) { if (!range.IsNull) { if (range.Count == 1 && childIndex.GetRow(range.Min) == row) return; if (row.HasKeyChanged(parentKey)) {// if key is not changed, this will not cause child to be stranded throw ExceptionBuilder.FailedCascadeUpdate(ConstraintName); } } } } } internal void CascadeUpdate(DataRow row) { if (-1 == row.newRecord) return; object[] currentKey = row.GetKeyValues(parentKey, DataRowVersion.Current); if (!Table.DataSet.fInReadXml && IsKeyNull(currentKey)) { return; } Index childIndex = childKey.GetSortIndex(); switch (UpdateRule) { case Rule.None: { if (row.Table.DataSet.EnforceConstraints) { // if we're not cascading deletes, we should throw if we're going to strand a child row under enforceConstraints. Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { throw ExceptionBuilder.FailedCascadeUpdate(ConstraintName); } } break; } case Rule.Cascade: { Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { object[] proposedKey = row.GetKeyValues(parentKey, DataRowVersion.Proposed); DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; rows[j].SetKeyValues(childKey, proposedKey); } } break; } case Rule.SetNull: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = DBNull.Value; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; rows[j].SetKeyValues(childKey, proposedKey); } } break; } case Rule.SetDefault: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = childKey.ColumnsReference[i].DefaultValue; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; rows[j].SetKeyValues(childKey, proposedKey); } } break; } default: { Debug.Assert(false, "Unknown Rule value"); break; } } } internal void CheckCanClearParentTable(DataTable table) { if (Table.DataSet.EnforceConstraints && Table.Rows.Count > 0) { throw ExceptionBuilder.FailedClearParentTable(table.TableName, ConstraintName, Table.TableName); } } internal void CheckCanRemoveParentRow(DataRow row) { Debug.Assert(Table.DataSet != null, "Relation " + ConstraintName + " isn't part of a DataSet, so this check shouldn't be happening."); if (!Table.DataSet.EnforceConstraints) return; if (DataRelation.GetChildRows(this.ParentKey, this.ChildKey, row, DataRowVersion.Default).Length > 0) { throw ExceptionBuilder.RemoveParentRow(this); } } internal void CheckCascade(DataRow row, DataRowAction action) { Debug.Assert(Table.DataSet != null, "ForeignKeyConstraint " + ConstraintName + " isn't part of a DataSet, so this check shouldn't be happening."); if (row.inCascade) return; row.inCascade = true; try { if (action == DataRowAction.Change) { if (row.HasKeyChanged(parentKey)) { CascadeUpdate(row); } } else if (action == DataRowAction.Delete) { CascadeDelete(row); } else if (action == DataRowAction.Commit) { CascadeCommit(row); } else if (action == DataRowAction.Rollback) { CascadeRollback(row); } else if (action == DataRowAction.Add) { } else { Debug.Assert(false, "attempt to cascade unknown action: " + ((Enum) action).ToString()); } } finally { row.inCascade = false; } } internal override void CheckConstraint(DataRow childRow, DataRowAction action) { if ((action == DataRowAction.Change || action == DataRowAction.Add || action == DataRowAction.Rollback) && Table.DataSet != null && Table.DataSet.EnforceConstraints && childRow.HasKeyChanged(childKey)) { // This branch is for cascading case verification. DataRowVersion version = (action == DataRowAction.Rollback) ? DataRowVersion.Original : DataRowVersion.Current; object[] childKeyValues = childRow.GetKeyValues(childKey); // check to see if this is just a change to my parent's proposed value. if (childRow.HasVersion(version)) { // this is the new proposed value for the parent. DataRow parentRow = DataRelation.GetParentRow(this.ParentKey, this.ChildKey, childRow, version); if(parentRow != null && parentRow.inCascade) { object[] parentKeyValues = parentRow.GetKeyValues(parentKey, action == DataRowAction.Rollback ? version : DataRowVersion.Default); int parentKeyValuesRecord = childRow.Table.NewRecord(); childRow.Table.SetKeyValues(childKey, parentKeyValues, parentKeyValuesRecord); if (childKey.RecordsEqual(childRow.tempRecord, parentKeyValuesRecord)) { return; } } } // now check to see if someone exists... it will have to be in a parent row's current, not a proposed. object[] childValues = childRow.GetKeyValues(childKey); if (!IsKeyNull(childValues)) { Index parentIndex = parentKey.GetSortIndex(); if (!parentIndex.IsKeyInIndex(childValues)) { // could be self-join constraint if (childKey.Table == parentKey.Table && childRow.tempRecord != -1) { int lo = 0; for (lo = 0; lo < childValues.Length; lo++) { DataColumn column = parentKey.ColumnsReference[lo]; object value = column.ConvertValue(childValues[lo]); if (0 != column.CompareValueTo(childRow.tempRecord, value)) { break; } } if (lo == childValues.Length) { return; } } throw ExceptionBuilder.ForeignKeyViolation(ConstraintName, childKeyValues); } } } } private void NonVirtualCheckState () { if (_DataSet == null) { // Make sure columns arrays are valid parentKey.CheckState(); childKey.CheckState(); if (parentKey.Table.DataSet != childKey.Table.DataSet) { throw ExceptionBuilder.TablesInDifferentSets(); } for (int i = 0; i < parentKey.ColumnsReference.Length; i++) { if (parentKey.ColumnsReference[i].DataType != childKey.ColumnsReference[i].DataType || ((parentKey.ColumnsReference[i].DataType == typeof(DateTime)) && (parentKey.ColumnsReference[i].DateTimeMode != childKey.ColumnsReference[i].DateTimeMode) && ((parentKey.ColumnsReference[i].DateTimeMode & childKey.ColumnsReference[i].DateTimeMode) != DataSetDateTime.Unspecified))) throw ExceptionBuilder.ColumnsTypeMismatch(); } if (childKey.ColumnsEqual(parentKey)) { throw ExceptionBuilder.KeyColumnsIdentical(); } } } // If we're not in a DataSet relations collection, we need to verify on every property get that we're // still a good relation object. internal override void CheckState() { NonVirtualCheckState (); } ////// Gets the child table of this constraint. /// ////// [ ResCategoryAttribute(Res.DataCategory_Data), DefaultValue(AcceptRejectRule_Default), ResDescriptionAttribute(Res.ForeignKeyConstraintAcceptRejectRuleDescr) ] public virtual AcceptRejectRule AcceptRejectRule { get { CheckStateForProperty(); return acceptRejectRule; } set { switch(value) { // @perfnote: Enum.IsDefined case AcceptRejectRule.None: case AcceptRejectRule.Cascade: this.acceptRejectRule = value; break; default: throw Common.ADP.InvalidAcceptRejectRule(value); } } } internal override bool ContainsColumn(DataColumn column) { return parentKey.ContainsColumn(column) || childKey.ContainsColumn(column); } internal override Constraint Clone(DataSet destination) { return Clone(destination, false); } internal override Constraint Clone(DataSet destination, bool ignorNSforTableLookup) { int iDest; if (ignorNSforTableLookup) { iDest = destination.Tables.IndexOf(Table.TableName); } else { iDest = destination.Tables.IndexOf(Table.TableName, Table.Namespace, false); // pass false for last param // to be backward compatable, otherwise meay cause new exception } if (iDest < 0) return null; DataTable table = destination.Tables[iDest]; if (ignorNSforTableLookup) { iDest = destination.Tables.IndexOf(RelatedTable.TableName); } else { iDest = destination.Tables.IndexOf(RelatedTable.TableName, RelatedTable.Namespace, false);// pass false for last param } if (iDest < 0) return null; DataTable relatedTable = destination.Tables[iDest]; int keys = Columns.Length; DataColumn[] columns = new DataColumn[keys]; DataColumn[] relatedColumns = new DataColumn[keys]; for (int i = 0; i < keys; i++) { DataColumn src = Columns[i]; iDest = table.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; columns[i] = table.Columns[iDest]; src = RelatedColumnsReference[i]; iDest = relatedTable.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; relatedColumns[i] = relatedTable.Columns[iDest]; } ForeignKeyConstraint clone = new ForeignKeyConstraint(ConstraintName,relatedColumns, columns); clone.UpdateRule = this.UpdateRule; clone.DeleteRule = this.DeleteRule; clone.AcceptRejectRule = this.AcceptRejectRule; // ...Extended Properties foreach(Object key in this.ExtendedProperties.Keys) { clone.ExtendedProperties[key]=this.ExtendedProperties[key]; } return clone; } internal ForeignKeyConstraint Clone(DataTable destination) { Debug.Assert(this.Table == this.RelatedTable, "We call this clone just if we have the same datatable as parent and child "); int keys = Columns.Length; DataColumn[] columns = new DataColumn[keys]; DataColumn[] relatedColumns = new DataColumn[keys]; int iDest =0; for (int i = 0; i < keys; i++) { DataColumn src = Columns[i]; iDest = destination.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; columns[i] = destination.Columns[iDest]; src = RelatedColumnsReference[i]; iDest = destination.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; relatedColumns[i] = destination.Columns[iDest]; } ForeignKeyConstraint clone = new ForeignKeyConstraint(ConstraintName, relatedColumns, columns); clone.UpdateRule = this.UpdateRule; clone.DeleteRule = this.DeleteRule; clone.AcceptRejectRule = this.AcceptRejectRule; // ...Extended Properties foreach(Object key in this.ExtendedProperties.Keys) { clone.ExtendedProperties[key]=this.ExtendedProperties[key]; } return clone; } private void Create(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns) { if (parentColumns.Length == 0 || childColumns.Length == 0) throw ExceptionBuilder.KeyLengthZero(); if (parentColumns.Length != childColumns.Length) throw ExceptionBuilder.KeyLengthMismatch(); for (int i = 0; i < parentColumns.Length; i++) { if (parentColumns[i].Computed) { throw ExceptionBuilder.ExpressionInConstraint(parentColumns[i]); } if (childColumns[i].Computed) { throw ExceptionBuilder.ExpressionInConstraint(childColumns[i]); } } this.parentKey = new DataKey(parentColumns, true); this.childKey = new DataKey(childColumns, true); ConstraintName = relationName; NonVirtualCheckState(); } ////// Indicates what kind of action should take place across /// this constraint when ////// is invoked. /// /// [ ResCategoryAttribute(Res.DataCategory_Data), DefaultValue(Rule_Default), ResDescriptionAttribute(Res.ForeignKeyConstraintDeleteRuleDescr) ] public virtual Rule DeleteRule { get { CheckStateForProperty(); return deleteRule; } set { switch(value) { // @perfnote: Enum.IsDefined case Rule.None: case Rule.Cascade: case Rule.SetNull: case Rule.SetDefault: this.deleteRule = value; break; default: throw Common.ADP.InvalidRule(value); } } } ///Gets /// or sets the action that occurs across this constraint when a row is deleted. ////// public override bool Equals(object key) { if (!(key is ForeignKeyConstraint)) return false; ForeignKeyConstraint key2 = (ForeignKeyConstraint) key; // The ParentKey and ChildKey completely identify the ForeignKeyConstraint return this.ParentKey.ColumnsEqual(key2.ParentKey) && this.ChildKey.ColumnsEqual(key2.ChildKey); } ///Gets a value indicating whether the current ///is identical to the specified object. /// public override Int32 GetHashCode() { return base.GetHashCode(); } ///[To be supplied.] ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ForeignKeyConstraintParentColumnsDescr), ReadOnly(true) ] public virtual DataColumn[] RelatedColumns { get { CheckStateForProperty(); return parentKey.ToArray(); } } internal DataColumn[] RelatedColumnsReference { get { CheckStateForProperty(); return parentKey.ColumnsReference; } } ////// The parent columns of this constraint. /// ////// The internal key object for the parent table. /// internal DataKey ParentKey { get { CheckStateForProperty(); return parentKey; } } internal DataRelation FindParentRelation () { DataRelationCollection rels = Table.ParentRelations; for (int i = 0; i < rels.Count; i++) { if (rels[i].ChildKeyConstraint == this) return rels[i]; } return null; } ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ForeignKeyRelatedTableDescr), ReadOnly(true) ] public virtual DataTable RelatedTable { get { CheckStateForProperty(); return parentKey.Table; } } ////// Gets the parent table of this constraint. /// ////// [ ResCategoryAttribute(Res.DataCategory_Data), DefaultValue(Rule_Default), ResDescriptionAttribute(Res.ForeignKeyConstraintUpdateRuleDescr) ] public virtual Rule UpdateRule { get { CheckStateForProperty(); return updateRule; } set { switch(value) { // @perfnote: Enum.IsDefined case Rule.None: case Rule.Cascade: case Rule.SetNull: case Rule.SetDefault: this.updateRule = value; break; default: throw Common.ADP.InvalidRule(value); } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //Gets or /// sets the action that occurs across this constraint on when a row is /// updated. ///// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //[....] //----------------------------------------------------------------------------- namespace System.Data { using System; using System.ComponentModel; using System.Diagnostics; using System.Data.Common; ////// [ DefaultProperty("ConstraintName"), Editor("Microsoft.VSDesigner.Data.Design.ForeignKeyConstraintEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing), ] #if WINFSInternalOnly internal #else public #endif class ForeignKeyConstraint : Constraint { // constants internal const Rule Rule_Default = Rule.Cascade; internal const AcceptRejectRule AcceptRejectRule_Default = AcceptRejectRule.None; // properties internal Rule deleteRule = Rule_Default; internal Rule updateRule = Rule_Default; internal AcceptRejectRule acceptRejectRule = AcceptRejectRule_Default; private DataKey childKey; private DataKey parentKey; // Design time serialization internal string constraintName = null; internal string[] parentColumnNames = null; internal string[] childColumnNames = null; internal string parentTableName = null; internal string parentTableNamespace = null; ///Represents an action /// restriction enforced on a set of columns in a primary key/foreign key relationship when /// a value or row is either deleted or updated. ////// public ForeignKeyConstraint(DataColumn parentColumn, DataColumn childColumn) : this(null, parentColumn, childColumn) { } ////// Initializes a new instance of the ///class with the specified parent and /// child objects. /// /// public ForeignKeyConstraint(string constraintName, DataColumn parentColumn, DataColumn childColumn) { DataColumn[] parentColumns = new DataColumn[] {parentColumn}; DataColumn[] childColumns = new DataColumn[] {childColumn}; Create(constraintName, parentColumns, childColumns); } ////// Initializes a new instance of the ///class with the specified name, /// parent and child objects. /// /// public ForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) : this(null, parentColumns, childColumns) { } ////// Initializes a new instance of the ///class with the specified arrays /// of parent and child objects. /// /// public ForeignKeyConstraint(string constraintName, DataColumn[] parentColumns, DataColumn[] childColumns) { Create(constraintName, parentColumns, childColumns); } // construct design time object ////// Initializes a new instance of the ///class with the specified name, /// and arrays of parent and child objects. /// /// [Browsable(false)] public ForeignKeyConstraint(string constraintName, string parentTableName, string[] parentColumnNames, string[] childColumnNames, AcceptRejectRule acceptRejectRule, Rule deleteRule, Rule updateRule) { this.constraintName = constraintName; this.parentColumnNames = parentColumnNames; this.childColumnNames = childColumnNames; this.parentTableName = parentTableName; this.acceptRejectRule = acceptRejectRule; this.deleteRule = deleteRule; this.updateRule = updateRule; // ForeignKeyConstraint(constraintName, parentTableName, null, parentColumnNames, childColumnNames,acceptRejectRule, deleteRule, updateRule) } // construct design time object [Browsable(false)] public ForeignKeyConstraint(string constraintName, string parentTableName, string parentTableNamespace, string[] parentColumnNames, string[] childColumnNames, AcceptRejectRule acceptRejectRule, Rule deleteRule, Rule updateRule) { this.constraintName = constraintName; this.parentColumnNames = parentColumnNames; this.childColumnNames = childColumnNames; this.parentTableName = parentTableName; this.parentTableNamespace= parentTableNamespace; this.acceptRejectRule = acceptRejectRule; this.deleteRule = deleteRule; this.updateRule = updateRule; } ///[To be supplied.] ////// The internal constraint object for the child table. /// internal DataKey ChildKey { get { CheckStateForProperty(); return childKey; } } ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ForeignKeyConstraintChildColumnsDescr), ReadOnly(true) ] public virtual DataColumn[] Columns { get { CheckStateForProperty(); return childKey.ToArray(); } } ////// Gets the child columns of this constraint. /// ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ConstraintTableDescr), ReadOnly(true) ] public override DataTable Table { get { CheckStateForProperty(); return childKey.Table; } } internal string[] ParentColumnNames { get { return parentKey.GetColumnNames(); } } internal string[] ChildColumnNames { get { return childKey.GetColumnNames(); } } internal override void CheckCanAddToCollection(ConstraintCollection constraints) { if (Table != constraints.Table) throw ExceptionBuilder.ConstraintAddFailed(constraints.Table); if (Table.Locale.LCID != RelatedTable.Locale.LCID || Table.CaseSensitive != RelatedTable.CaseSensitive) throw ExceptionBuilder.CaseLocaleMismatch(); } internal override bool CanBeRemovedFromCollection(ConstraintCollection constraints, bool fThrowException) { return true; } internal bool IsKeyNull( object[] values ) { for (int i = 0; i < values.Length; i++) { if (! DataStorage.IsObjectNull(values[i])) return false; } return true; } internal override bool IsConstraintViolated() { Index childIndex = childKey.GetSortIndex(); object[] uniqueChildKeys = childIndex.GetUniqueKeyValues(); bool errors = false; Index parentIndex = parentKey.GetSortIndex(); for (int i = 0; i < uniqueChildKeys.Length; i++) { object[] childValues = (object[]) uniqueChildKeys[i]; if (!IsKeyNull(childValues)) { if (!parentIndex.IsKeyInIndex(childValues)) { DataRow[] rows = childIndex.GetRows(childIndex.FindRecords(childValues)); string error = Res.GetString(Res.DataConstraint_ForeignKeyViolation, ConstraintName, ExceptionBuilder.KeysToString(childValues)); for (int j = 0; j < rows.Length; j++) { rows[j].RowError = error; } errors = true; } } } return errors; } internal override bool CanEnableConstraint() { if (Table.DataSet == null || !Table.DataSet.EnforceConstraints) return true; Index childIndex = childKey.GetSortIndex(); object[] uniqueChildKeys = childIndex.GetUniqueKeyValues(); Index parentIndex = parentKey.GetSortIndex(); for (int i = 0; i < uniqueChildKeys.Length; i++) { object[] childValues = (object[]) uniqueChildKeys[i]; if (!IsKeyNull(childValues) && !parentIndex.IsKeyInIndex(childValues)) { return false; } } return true; } internal void CascadeCommit(DataRow row) { if (row.RowState == DataRowState.Detached) return; if (acceptRejectRule == AcceptRejectRule.Cascade) { Index childIndex = childKey.GetSortIndex( row.RowState == DataRowState.Deleted ? DataViewRowState.Deleted : DataViewRowState.CurrentRows ); object[] key = row.GetKeyValues(parentKey, row.RowState == DataRowState.Deleted ? DataRowVersion.Original : DataRowVersion.Default ); if (IsKeyNull(key)) { return; } Range range = childIndex.FindRecords(key); if (!range.IsNull) { // SQLBU 499726 - DataTable internal index is corrupted: '13' // Self-referencing table has suspendIndexEvents, in the multi-table scenario the child table hasn't // this allows the self-ref table to maintain the index while in the child-table doesn't DataRow[] rows = childIndex.GetRows(range); foreach(DataRow childRow in rows) { if (DataRowState.Detached != childRow.RowState) { if (childRow.inCascade) continue; childRow.AcceptChanges(); } } } } } internal void CascadeDelete(DataRow row) { if (-1 == row.newRecord) return; object[] currentKey = row.GetKeyValues(parentKey, DataRowVersion.Current); if (IsKeyNull(currentKey)) { return; } Index childIndex = childKey.GetSortIndex(); switch (DeleteRule) { case Rule.None: { if (row.Table.DataSet.EnforceConstraints) { // if we're not cascading deletes, we should throw if we're going to strand a child row under enforceConstraints. Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { if (range.Count == 1 && childIndex.GetRow(range.Min) == row) return; throw ExceptionBuilder.FailedCascadeDelete(ConstraintName); } } break; } case Rule.Cascade: { object[] key = row.GetKeyValues(parentKey, DataRowVersion.Default); Range range = childIndex.FindRecords(key); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { DataRow r = rows[j]; if (r.inCascade) continue; r.Table.DeleteRow(r); } } break; } case Rule.SetNull: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = DBNull.Value; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; if (row != rows[j]) rows[j].SetKeyValues(childKey, proposedKey); } } break; } case Rule.SetDefault: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = childKey.ColumnsReference[i].DefaultValue; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; if (row != rows[j]) rows[j].SetKeyValues(childKey, proposedKey); } } break; } default: { Debug.Assert(false, "Unknown Rule value"); break; } } } internal void CascadeRollback(DataRow row) { Index childIndex = childKey.GetSortIndex( row.RowState == DataRowState.Deleted ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows); object[] key = row.GetKeyValues(parentKey, row.RowState == DataRowState.Modified ? DataRowVersion.Current : DataRowVersion.Default ); // Bug : This is definitely not a proper fix. (Ref. MDAC Bug 73592) if (IsKeyNull(key)) { return; } Range range = childIndex.FindRecords(key); if (acceptRejectRule == AcceptRejectRule.Cascade) { if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { if (rows[j].inCascade) continue; rows[j].RejectChanges(); } } } else { // AcceptRejectRule.None if (row.RowState != DataRowState.Deleted && row.Table.DataSet.EnforceConstraints) { if (!range.IsNull) { if (range.Count == 1 && childIndex.GetRow(range.Min) == row) return; if (row.HasKeyChanged(parentKey)) {// if key is not changed, this will not cause child to be stranded throw ExceptionBuilder.FailedCascadeUpdate(ConstraintName); } } } } } internal void CascadeUpdate(DataRow row) { if (-1 == row.newRecord) return; object[] currentKey = row.GetKeyValues(parentKey, DataRowVersion.Current); if (!Table.DataSet.fInReadXml && IsKeyNull(currentKey)) { return; } Index childIndex = childKey.GetSortIndex(); switch (UpdateRule) { case Rule.None: { if (row.Table.DataSet.EnforceConstraints) { // if we're not cascading deletes, we should throw if we're going to strand a child row under enforceConstraints. Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { throw ExceptionBuilder.FailedCascadeUpdate(ConstraintName); } } break; } case Rule.Cascade: { Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { object[] proposedKey = row.GetKeyValues(parentKey, DataRowVersion.Proposed); DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; rows[j].SetKeyValues(childKey, proposedKey); } } break; } case Rule.SetNull: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = DBNull.Value; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; rows[j].SetKeyValues(childKey, proposedKey); } } break; } case Rule.SetDefault: { object[] proposedKey = new object[childKey.ColumnsReference.Length]; for (int i = 0; i < childKey.ColumnsReference.Length; i++) proposedKey[i] = childKey.ColumnsReference[i].DefaultValue; Range range = childIndex.FindRecords(currentKey); if (!range.IsNull) { DataRow[] rows = childIndex.GetRows(range); for (int j = 0; j < rows.Length; j++) { // if (rows[j].inCascade) // continue; rows[j].SetKeyValues(childKey, proposedKey); } } break; } default: { Debug.Assert(false, "Unknown Rule value"); break; } } } internal void CheckCanClearParentTable(DataTable table) { if (Table.DataSet.EnforceConstraints && Table.Rows.Count > 0) { throw ExceptionBuilder.FailedClearParentTable(table.TableName, ConstraintName, Table.TableName); } } internal void CheckCanRemoveParentRow(DataRow row) { Debug.Assert(Table.DataSet != null, "Relation " + ConstraintName + " isn't part of a DataSet, so this check shouldn't be happening."); if (!Table.DataSet.EnforceConstraints) return; if (DataRelation.GetChildRows(this.ParentKey, this.ChildKey, row, DataRowVersion.Default).Length > 0) { throw ExceptionBuilder.RemoveParentRow(this); } } internal void CheckCascade(DataRow row, DataRowAction action) { Debug.Assert(Table.DataSet != null, "ForeignKeyConstraint " + ConstraintName + " isn't part of a DataSet, so this check shouldn't be happening."); if (row.inCascade) return; row.inCascade = true; try { if (action == DataRowAction.Change) { if (row.HasKeyChanged(parentKey)) { CascadeUpdate(row); } } else if (action == DataRowAction.Delete) { CascadeDelete(row); } else if (action == DataRowAction.Commit) { CascadeCommit(row); } else if (action == DataRowAction.Rollback) { CascadeRollback(row); } else if (action == DataRowAction.Add) { } else { Debug.Assert(false, "attempt to cascade unknown action: " + ((Enum) action).ToString()); } } finally { row.inCascade = false; } } internal override void CheckConstraint(DataRow childRow, DataRowAction action) { if ((action == DataRowAction.Change || action == DataRowAction.Add || action == DataRowAction.Rollback) && Table.DataSet != null && Table.DataSet.EnforceConstraints && childRow.HasKeyChanged(childKey)) { // This branch is for cascading case verification. DataRowVersion version = (action == DataRowAction.Rollback) ? DataRowVersion.Original : DataRowVersion.Current; object[] childKeyValues = childRow.GetKeyValues(childKey); // check to see if this is just a change to my parent's proposed value. if (childRow.HasVersion(version)) { // this is the new proposed value for the parent. DataRow parentRow = DataRelation.GetParentRow(this.ParentKey, this.ChildKey, childRow, version); if(parentRow != null && parentRow.inCascade) { object[] parentKeyValues = parentRow.GetKeyValues(parentKey, action == DataRowAction.Rollback ? version : DataRowVersion.Default); int parentKeyValuesRecord = childRow.Table.NewRecord(); childRow.Table.SetKeyValues(childKey, parentKeyValues, parentKeyValuesRecord); if (childKey.RecordsEqual(childRow.tempRecord, parentKeyValuesRecord)) { return; } } } // now check to see if someone exists... it will have to be in a parent row's current, not a proposed. object[] childValues = childRow.GetKeyValues(childKey); if (!IsKeyNull(childValues)) { Index parentIndex = parentKey.GetSortIndex(); if (!parentIndex.IsKeyInIndex(childValues)) { // could be self-join constraint if (childKey.Table == parentKey.Table && childRow.tempRecord != -1) { int lo = 0; for (lo = 0; lo < childValues.Length; lo++) { DataColumn column = parentKey.ColumnsReference[lo]; object value = column.ConvertValue(childValues[lo]); if (0 != column.CompareValueTo(childRow.tempRecord, value)) { break; } } if (lo == childValues.Length) { return; } } throw ExceptionBuilder.ForeignKeyViolation(ConstraintName, childKeyValues); } } } } private void NonVirtualCheckState () { if (_DataSet == null) { // Make sure columns arrays are valid parentKey.CheckState(); childKey.CheckState(); if (parentKey.Table.DataSet != childKey.Table.DataSet) { throw ExceptionBuilder.TablesInDifferentSets(); } for (int i = 0; i < parentKey.ColumnsReference.Length; i++) { if (parentKey.ColumnsReference[i].DataType != childKey.ColumnsReference[i].DataType || ((parentKey.ColumnsReference[i].DataType == typeof(DateTime)) && (parentKey.ColumnsReference[i].DateTimeMode != childKey.ColumnsReference[i].DateTimeMode) && ((parentKey.ColumnsReference[i].DateTimeMode & childKey.ColumnsReference[i].DateTimeMode) != DataSetDateTime.Unspecified))) throw ExceptionBuilder.ColumnsTypeMismatch(); } if (childKey.ColumnsEqual(parentKey)) { throw ExceptionBuilder.KeyColumnsIdentical(); } } } // If we're not in a DataSet relations collection, we need to verify on every property get that we're // still a good relation object. internal override void CheckState() { NonVirtualCheckState (); } ////// Gets the child table of this constraint. /// ////// [ ResCategoryAttribute(Res.DataCategory_Data), DefaultValue(AcceptRejectRule_Default), ResDescriptionAttribute(Res.ForeignKeyConstraintAcceptRejectRuleDescr) ] public virtual AcceptRejectRule AcceptRejectRule { get { CheckStateForProperty(); return acceptRejectRule; } set { switch(value) { // @perfnote: Enum.IsDefined case AcceptRejectRule.None: case AcceptRejectRule.Cascade: this.acceptRejectRule = value; break; default: throw Common.ADP.InvalidAcceptRejectRule(value); } } } internal override bool ContainsColumn(DataColumn column) { return parentKey.ContainsColumn(column) || childKey.ContainsColumn(column); } internal override Constraint Clone(DataSet destination) { return Clone(destination, false); } internal override Constraint Clone(DataSet destination, bool ignorNSforTableLookup) { int iDest; if (ignorNSforTableLookup) { iDest = destination.Tables.IndexOf(Table.TableName); } else { iDest = destination.Tables.IndexOf(Table.TableName, Table.Namespace, false); // pass false for last param // to be backward compatable, otherwise meay cause new exception } if (iDest < 0) return null; DataTable table = destination.Tables[iDest]; if (ignorNSforTableLookup) { iDest = destination.Tables.IndexOf(RelatedTable.TableName); } else { iDest = destination.Tables.IndexOf(RelatedTable.TableName, RelatedTable.Namespace, false);// pass false for last param } if (iDest < 0) return null; DataTable relatedTable = destination.Tables[iDest]; int keys = Columns.Length; DataColumn[] columns = new DataColumn[keys]; DataColumn[] relatedColumns = new DataColumn[keys]; for (int i = 0; i < keys; i++) { DataColumn src = Columns[i]; iDest = table.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; columns[i] = table.Columns[iDest]; src = RelatedColumnsReference[i]; iDest = relatedTable.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; relatedColumns[i] = relatedTable.Columns[iDest]; } ForeignKeyConstraint clone = new ForeignKeyConstraint(ConstraintName,relatedColumns, columns); clone.UpdateRule = this.UpdateRule; clone.DeleteRule = this.DeleteRule; clone.AcceptRejectRule = this.AcceptRejectRule; // ...Extended Properties foreach(Object key in this.ExtendedProperties.Keys) { clone.ExtendedProperties[key]=this.ExtendedProperties[key]; } return clone; } internal ForeignKeyConstraint Clone(DataTable destination) { Debug.Assert(this.Table == this.RelatedTable, "We call this clone just if we have the same datatable as parent and child "); int keys = Columns.Length; DataColumn[] columns = new DataColumn[keys]; DataColumn[] relatedColumns = new DataColumn[keys]; int iDest =0; for (int i = 0; i < keys; i++) { DataColumn src = Columns[i]; iDest = destination.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; columns[i] = destination.Columns[iDest]; src = RelatedColumnsReference[i]; iDest = destination.Columns.IndexOf(src.ColumnName); if (iDest < 0) return null; relatedColumns[i] = destination.Columns[iDest]; } ForeignKeyConstraint clone = new ForeignKeyConstraint(ConstraintName, relatedColumns, columns); clone.UpdateRule = this.UpdateRule; clone.DeleteRule = this.DeleteRule; clone.AcceptRejectRule = this.AcceptRejectRule; // ...Extended Properties foreach(Object key in this.ExtendedProperties.Keys) { clone.ExtendedProperties[key]=this.ExtendedProperties[key]; } return clone; } private void Create(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns) { if (parentColumns.Length == 0 || childColumns.Length == 0) throw ExceptionBuilder.KeyLengthZero(); if (parentColumns.Length != childColumns.Length) throw ExceptionBuilder.KeyLengthMismatch(); for (int i = 0; i < parentColumns.Length; i++) { if (parentColumns[i].Computed) { throw ExceptionBuilder.ExpressionInConstraint(parentColumns[i]); } if (childColumns[i].Computed) { throw ExceptionBuilder.ExpressionInConstraint(childColumns[i]); } } this.parentKey = new DataKey(parentColumns, true); this.childKey = new DataKey(childColumns, true); ConstraintName = relationName; NonVirtualCheckState(); } ////// Indicates what kind of action should take place across /// this constraint when ////// is invoked. /// /// [ ResCategoryAttribute(Res.DataCategory_Data), DefaultValue(Rule_Default), ResDescriptionAttribute(Res.ForeignKeyConstraintDeleteRuleDescr) ] public virtual Rule DeleteRule { get { CheckStateForProperty(); return deleteRule; } set { switch(value) { // @perfnote: Enum.IsDefined case Rule.None: case Rule.Cascade: case Rule.SetNull: case Rule.SetDefault: this.deleteRule = value; break; default: throw Common.ADP.InvalidRule(value); } } } ///Gets /// or sets the action that occurs across this constraint when a row is deleted. ////// public override bool Equals(object key) { if (!(key is ForeignKeyConstraint)) return false; ForeignKeyConstraint key2 = (ForeignKeyConstraint) key; // The ParentKey and ChildKey completely identify the ForeignKeyConstraint return this.ParentKey.ColumnsEqual(key2.ParentKey) && this.ChildKey.ColumnsEqual(key2.ChildKey); } ///Gets a value indicating whether the current ///is identical to the specified object. /// public override Int32 GetHashCode() { return base.GetHashCode(); } ///[To be supplied.] ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ForeignKeyConstraintParentColumnsDescr), ReadOnly(true) ] public virtual DataColumn[] RelatedColumns { get { CheckStateForProperty(); return parentKey.ToArray(); } } internal DataColumn[] RelatedColumnsReference { get { CheckStateForProperty(); return parentKey.ColumnsReference; } } ////// The parent columns of this constraint. /// ////// The internal key object for the parent table. /// internal DataKey ParentKey { get { CheckStateForProperty(); return parentKey; } } internal DataRelation FindParentRelation () { DataRelationCollection rels = Table.ParentRelations; for (int i = 0; i < rels.Count; i++) { if (rels[i].ChildKeyConstraint == this) return rels[i]; } return null; } ////// [ ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.ForeignKeyRelatedTableDescr), ReadOnly(true) ] public virtual DataTable RelatedTable { get { CheckStateForProperty(); return parentKey.Table; } } ////// Gets the parent table of this constraint. /// ////// [ ResCategoryAttribute(Res.DataCategory_Data), DefaultValue(Rule_Default), ResDescriptionAttribute(Res.ForeignKeyConstraintUpdateRuleDescr) ] public virtual Rule UpdateRule { get { CheckStateForProperty(); return updateRule; } set { switch(value) { // @perfnote: Enum.IsDefined case Rule.None: case Rule.Cascade: case Rule.SetNull: case Rule.SetDefault: this.updateRule = value; break; default: throw Common.ADP.InvalidRule(value); } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.Gets or /// sets the action that occurs across this constraint on when a row is /// updated. ///
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlCacheDependencySection.cs
- ValueUtilsSmi.cs
- MessageProperties.cs
- LogEntrySerializationException.cs
- safelinkcollection.cs
- RenderingEventArgs.cs
- ToolStripContentPanel.cs
- ContentElement.cs
- ToolStripSplitButton.cs
- ScrollItemPattern.cs
- ContainerParaClient.cs
- InvalidFilterCriteriaException.cs
- CellTreeNodeVisitors.cs
- ScrollEvent.cs
- QueryOperator.cs
- SequenceDesigner.cs
- Geometry.cs
- PipelineModuleStepContainer.cs
- DataServiceProviderWrapper.cs
- ObjectConverter.cs
- Timer.cs
- Int64Converter.cs
- ServiceBusyException.cs
- ElementAction.cs
- RegexInterpreter.cs
- ProjectionCamera.cs
- SqlFacetAttribute.cs
- DataColumnPropertyDescriptor.cs
- TreeNodeCollectionEditor.cs
- OutputCacheEntry.cs
- BlurBitmapEffect.cs
- mediapermission.cs
- ExpressionValueEditor.cs
- AvTraceFormat.cs
- DeflateEmulationStream.cs
- DataGridTextBox.cs
- RectAnimationBase.cs
- ClientEndpointLoader.cs
- XmlCharacterData.cs
- IconConverter.cs
- DataGridViewComboBoxColumnDesigner.cs
- WebPartDesigner.cs
- CellLabel.cs
- EntityDataReader.cs
- Attribute.cs
- SocketManager.cs
- ISAPIRuntime.cs
- Simplifier.cs
- Vertex.cs
- RuntimeDelegateArgument.cs
- ElementsClipboardData.cs
- MinMaxParagraphWidth.cs
- XmlSchema.cs
- SchemaInfo.cs
- FileSystemEventArgs.cs
- WindowsListViewItem.cs
- ContextStack.cs
- NullableConverter.cs
- InkPresenter.cs
- QilList.cs
- EntityAdapter.cs
- Condition.cs
- WinEventTracker.cs
- EventPropertyMap.cs
- StoreItemCollection.cs
- ServiceCredentials.cs
- WebPartAuthorizationEventArgs.cs
- MobileControlsSection.cs
- VersionConverter.cs
- MimeObjectFactory.cs
- LinqDataSourceContextEventArgs.cs
- ServicePointManagerElement.cs
- SymbolType.cs
- ActivationProxy.cs
- XmlSchemaSimpleTypeList.cs
- ResumeStoryboard.cs
- TreeView.cs
- XmlSerializerFactory.cs
- XmlElementList.cs
- CompensateDesigner.cs
- DiscoveryClientElement.cs
- HttpRuntime.cs
- TextElementCollectionHelper.cs
- DBDataPermission.cs
- OracleFactory.cs
- FunctionDetailsReader.cs
- WSMessageEncoding.cs
- DesignerActionList.cs
- CommandConverter.cs
- XmlTextReaderImplHelpers.cs
- CapabilitiesSection.cs
- backend.cs
- _NegotiateClient.cs
- ObservableCollection.cs
- altserialization.cs
- ServerIdentity.cs
- XsltArgumentList.cs
- DodSequenceMerge.cs
- HostProtectionPermission.cs
- XPathNavigatorKeyComparer.cs