テーブルのデータに制限を強制するために、制約を設定できます。
DataTable.Constraintsの戻り値の型はConstraintCollectionであり、その要素の型はConstraintです。よってそこからUniqueConstraintまたはForeignKeyConstraintを得るには、キャストが必要です。
すべての値が唯一でなければならない列の組の、制約を表します。UniqueConstraint Class (System.Data) | Microsoft Learn
型 | プロパティ | 内容 |
---|---|---|
DataColumn[] | Columns | |
bool | IsPrimaryKey | |
DataSet.EnforceConstraintsがfalseに設定されている間は、この制約は強制されません。
DataTable table = new DataTable(); DataColumn column = table.Columns.Add("id"); int c1 = table.Constraints.Count; // 0 column.Unique = true; // Uniqueを trueとすることで、制約に追加される int c2 = table.Constraints.Count; // 1 UniqueConstraint constraint = (UniqueConstraint)table.Constraints[0]; string name = constraint.ConstraintName; // "Constraint1" int length = constraint.Columns.Length; // 1 string columnName = constraint.Columns[0].ColumnName; // "id" table.Rows.Add(0); table.Rows.Add(0); // ConstraintException「列 'id' は一意であるように制約されています。値 '0' は既に存在します。
コレクションに制約を追加できるConstraintCollection.Add()、
public System.Data.Constraint Add (
string name,
System.Data.DataColumn column,
bool primaryKey // columnをPrimaryKeyとするならば、trueを指定する
);
Add(String, DataColumn, Boolean) - ConstraintCollection.Add Method (System.Data) | Microsoft Learn
を用いれば、追加時にそのインスタンスを取得できます。
DataTable table = new DataTable(); DataColumn column = table.Columns.Add("id"); UniqueConstraint constraint = (UniqueConstraint)table.Constraints.Add("sample", column, false); string name = constraint.ConstraintName; // "sample" bool unique = column.Unique; // true
この制約に追加すると、追加した列のUniqueがtrueとなります。
型 | プロパティ | 内容 |
---|---|---|
string | ConstraintName | ConstraintCollection内での、制約の名前 |
Rule | DeleteRule | 親テーブルから行が削除されたときの、子テーブルの動作
DataRowCollection.Remove()による除去は内部でAcceptChanges()を呼ぶため、このプロパティではなくAcceptRejectRuleに影響される |
Rule | UpdateRule | 親テーブルの行が更新されたときの、子テーブルの動作 |
AcceptRejectRule | AcceptRejectRule | 親テーブルでAcceptChanges()が呼ばれたときの、子テーブルの動作 |
この制約を指定した行が、親行の影響を受けるようになります。つまり制約は、子テーブルの側に指定します。
親テーブルの行と関連のない子テーブルの行は、制約の影響を受けません。これには子テーブルのNewRow()で作成した、子テーブルに追加する前の行などが該当します。
列挙子 | 数値 | 内容 |
---|---|---|
None | 0 | 関連する行に、何もしない |
Cascade | 1 | 関連する行を、削除または更新する [既定]
Relationに指定されている列が更新されると、その子行の列もその値に更新される ※1 |
SetDefault | 3 | 関連する行の値を、DataColumn.DefaultValueの値にする |
SetNull | 2 | 関連する行の値を、DBNullにする |
※1 Relationに指定されている列があるにもかかわらずDeleteRuleがCascadeに設定されていないと、その列の値を変更したときに「制約がリレーションシップ Relation で適用され、この値を変更すると子行が孤立するため、変更できません。」としてInvalidConstraintExceptionが投げられます。
AcceptChanges()が呼ばれたときの制約を表します。ForeignKeyConstraint.AcceptRejectRule Property (System.Data) | Microsoft Learn
このAcceptChanges()はDataTable.LoadDataRow()やDataRowCollection.Remove()の内部からも呼ばれるため、この制約はこれらのメソッドにも作用します。AcceptChanges - AcceptChanges
ドキュメントにはありませんが、プロパティ名にあるようにRejectChanges()にも影響します。
列挙子 | 数値 | 内容 |
---|---|---|
None | 0 | No action occurs [既定] |
Cascade | 1 | Changes are cascaded across the relationship. |
DataSet dataSet = new DataSet(); DataTable tableA = dataSet.Tables.Add(); DataTable tableB = dataSet.Tables.Add(); DataRelation relation = dataSet.Relations.Add( tableA.Columns.Add(), tableB.Columns.Add()); DataRow rowA = tableA.Rows.Add("1"); DataRow rowB = tableB.Rows.Add("1"); ForeignKeyConstraint constraint = relation.ChildKeyConstraint; string name = constraint.ConstraintName; // "Relation1" Rule rule1 = constraint.DeleteRule; // Cascade Rule rule2 = constraint.UpdateRule; // Cascade AcceptRejectRule rule1 = constraint.AcceptRejectRule; // None
このAcceptRejectRuleがNoneの状態ではAcceptChanges()は子テーブルに作用しませんが、Cascadeとすると作用するようになります。
DataRowState stateA1 = rowA.RowState; // Added DataRowState stateB1 = rowB.RowState; // Added rowA.AcceptChanges(); DataRowState stateA2 = rowA.RowState; // Unchanged DataRowState stateB2 = rowB.RowState; // Added. 子テーブルには作用しない rowA.SetAdded(); // rowA.RowStateを Addedに戻す constraint.AcceptRejectRule = AcceptRejectRule.Cascade; rowA.AcceptChanges(); DataRowState stateA3 = rowA.RowState; // Unchanged DataRowState stateB3 = rowB.RowState; // Unchanged. 子テーブルにも作用している