DataExceptionクラスはADO.NETで生成されるエラーを表す例外の基本クラスであり、以下に示すクラスがこれから派生しています。
「制約を有効にできませんでした。行に入力できるのは、Null 以外の値、一意な値、あるいは外部キーですが、この制約の違反が 1 つ以上の行で発生しています。」
DataSet.EnforceConstraintsをfalseとすることで、制約を一時的に無効にできます。ただしそのときはそれをtrueに戻す前に制約に違反しない状態にしておかないと、trueにした時点でConstraintExceptionが投げられます。Remarks - ConstraintException Class (System.Data) | Microsoft Learn
「列 '***' は一意であるように制約されています。値 '***' は既に存在します。」
DataTable table = new DataTable();
DataColumn column = table.Columns.Add();
column.Unique = true;
table.Rows.Add("A");
table.Rows.Add("A"); // ConstraintException「列 'Column1' は一意であるように制約されています。値 'A' は既に存在します。」
「ForeignKeyConstraint ConstraintName には親テーブルに存在している子キー値 (***) が必要です。」
DataSet dataSet = new DataSet(); DataTable tableA = dataSet.Tables.Add(); DataTable tableB = dataSet.Tables.Add(); dataSet.Relations.Add( tableA.Columns.Add(), tableB.Columns.Add()); tableA.Rows.Add("1"); tableB.Rows.Add("1"); // ok tableB.Rows.Add("2"); // InvalidConstraintException「ForeignKeyConstraint Relation1 には親テーブルに存在している子キー値 (2) が必要です。」
このときDataRowを先に追加していると、DataRelationを設定したときに「対応する親の値が指定されてない値があるため、この制約を有効にできません。」としてArgumentExceptionが投げられます。
tableB.Rows.Add("2");
dataSet.Relations.Add( // ArgumentException
tableA.Columns.Add(),
tableB.Columns.Add());
「制約がリレーションシップ Relation で適用され、この値を変更すると子行が孤立するため、変更できません。(Cannot make this change because constraints are enforced on relation Relation, and changing this value will strand child rows.)」
「'ColumnName' という列は既にこの DataTable に属しています。(A column named 'ColumnName' already belongs to this DataTable.)」
この例外の直前に、「同一のキーを含む項目が既に追加されています。(An item with the same key has already been added.)」としてArgumentExceptionも投げられます。
table.Columns.Add("col");
table.Columns.Add("col"); // DuplicateNameException
この例外はDelete()またはDataRowCollection.Remove()で行が削除されている 行のRowStateがDetachedのとき、以下のメソッドが呼ばれたときに投げられます。Remarks - RowNotInTableException Class (System.Data) | Microsoft Learn
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("a"); DataRow rowB = tableB.Rows.Add("a"); rowA.AcceptChanges(); rowB.AcceptChanges(); rowA.Delete(); DataRowState state1 = rowA.RowState; // Deleted DataRow[] rows1 = rowA.GetChildRows(relation); // Deletedであるため、DeletedRowInaccessibleExceptionが投げられる DataRow row1b = rowB.GetParentRow(relation); // ok DataRow[] rows1b = rowB.GetParentRows(relation); // DeletedRowInaccessibleException rowA.AcceptChanges(); // Deletedであるため、問題ない DataRowState state2 = rowA.RowState; // Detached rowA.AcceptChanges(); // RowNotInTableException DataRow[] rows2 = rowA.GetChildRows(relation); // RowNotInTableException
「テーブルにない行でこの操作を実行することはできません。」
DataTable table = new DataTable(); DataRow row = table.Rows.Add(); row.Delete(); // RowState: Detached row.AcceptChanges(); // RowNotInTableException「テーブルにない行でこの操作を実行することはできません。」 row.RejectChanges(); // ok
削除していなくても、テーブルに追加しておらずRowStateがDetachedならば発生します。
DataTable table = new DataTable(); DataRow row = table.NewRow(); // RowState: Detached row.AcceptChanges(); // RowNotInTableException
「この行はテーブルから削除されており、データは含まれていません。BeginEdit() を使うとこの行に新しいデータを作成することができます。」
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"); rowA.Delete(); // RowState: Detached DataRowState state = rowB.RowState; // Detached DataRow[] rowsA = rowA.GetChildRows(relation); // RowNotInTableException「この行はテーブルから削除されており、データは含まれていません。BeginEdit() を使うとこの行に新しいデータを作成することができます。」 rowB.SetParentRow(rowA); // RowNotInTableException DataRow r1 = rowB.GetParentRow(relation); // ok DataRow[] r2 = rowB.GetParentRows(relation); // RowNotInTableException
Delete()などで行が削除されていても、そのRowStateがDeletedならば、RowNotInTableExceptionではなくDeletedRowInaccessibleExceptionが投げられます。
... rowB.AcceptChanges(); rowB.Delete(); // RowState: Deleted rowA.AcceptChanges(); rowA.Delete(); // RowState: Deleted DataRow[] rowsA = rowA.GetChildRows(relation); // DeletedRowInaccessibleException rowB.SetParentRow(rowA); // DeletedRowInaccessibleException DataRow r1 = rowB.GetParentRow(relation); // ok DataRow[] r2 = rowB.GetParentRows(relation); // DeletedRowInaccessibleException
なお同様にRowStateがDeletedのときにAcceptChanges()を呼ぶと、それが確定されてDetachedになるため例外は投げられません。
DataTable table = new DataTable(); DataRow row = table.Rows.Add(); row.AcceptChanges(); row.Delete(); // RowState: Deleted row.AcceptChanges(); // RowState: Detached
DataRow.Item[]やDataRow.ItemArrayから読み込むとき、RowStateがDetachedのときはRowNotInTableExceptionが投げられます。
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.Rows.Add(); row.Delete(); // RowState: Detached object data1 = row[0]; // RowNotInTableException「この行はテーブルから削除されており、データは含まれていません。BeginEdit() を使うとこの行に新しいデータを作成することができます。」 object[] items1 = row.ItemArray; // RowNotInTableException row[0] = 1; // ok object data2 = row[0]; // ok. 値を設定した後ならば取得できる object[] items2 = row.ItemArray; // ok
Field<T>()やSetField<T>()も内部ではDataRow.Item[]へアクセスしているため、同様に例外が発生します。
object data1 = row.Field<object>(0); // RowNotInTableException「この行はテーブルから削除されており、データは含まれていません。BeginEdit() を使うとこの行に新しいデータを作成することができます。」 row.SetField(0, 1); // ok object data2 = row.Field<object>(0); // ok
この例外は、内部では列のインデックスを取得するためのGetDefaultRecord()から投げられます。this - DataRow.cs
コレクションに含まれていない行を除去しようとした場合などは、「指定された DataRow は現在の DataRowCollection ではありません。(The given DataRow is not in the current DataRowCollection.)」として、DataExceptionから派生していない例外IndexOutOfRangeExceptionが投げられます。Remove - DataRowCollection.cs
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.Rows.Add(1); table.Rows.Remove(row); table.Rows.Remove(row); // IndexOutOfRangeException
この例外はRowStateがDeletedである行の値を、以下のプロパティやメソッドで取得や設定しようとするときに投げられます。Remarks - DeletedRowInaccessibleException Class (System.Data) | Microsoft Learn
RowStateがDeletedならば、DataRow.GetChildRows()などでもこの例外が投げられます。
DataRowCollection.Remove()で除去するときも、内部ではDataRow.Delete()が呼ばれることがあるため、一時的にRowStateがDeletedになる可能性があります。Remove - DataRowCollection.cs
「削除された行を通して、その行の情報にアクセスすることはできません。」
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.Rows.Add(); row.AcceptChanges(); row.Delete(); // RowState: Deleted row[0] = 1; // DeletedRowInaccessibleexception「削除された行を通して、その行の情報にアクセスすることはできません。」 object p1 = row[0]; // DeletedRowInaccessibleexception row.SetField(0, 2); // DeletedRowInaccessibleexception object f1 = row.Field<object>(0); // DeletedRowInaccessibleexception row.RowError = "a"; // ok string e1 = row.RowError; // ok row.AcceptChanges(); // ok. RowState: Detached object p2 = row[0]; // RowNotInTableException object f2 = row.Field<object>(0); // RowNotInTableException string e2 = row.RowError; // ok row[0] = 1; // ok row.SetField(0, 2); // ok row.RowError = "b"; // ok
存在しないDataRowのバージョンを得ようとするときに投げられます。
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.Rows.Add(); object obj1 = row[0, DataRowVersion.Current]; // ok object obj2 = row[0, DataRowVersion.Original]; // VersionNotFoundException「アクセスする Original データがありません。」 object obj3 = row[0, DataRowVersion.Proposed]; // VersionNotFoundException「アクセスする Proposed データがありません。」