DataExceptionクラス

DataExceptionクラスはADO.NETで生成されるエラーを表す例外の基本クラスであり、以下に示すクラスがこれから派生しています。

  • ConstraintException
  • DeletedRowInaccessibleException
  • Design.TypedDataSetGeneratorException
  • DuplicateNameException
  • EntityException
  • InRowChangingEventException
  • InvalidCommandTreeException
  • InvalidConstraintException
  • InvalidExpressionException
  • MissingPrimaryKeyException
  • NoNullAllowedException
  • ObjectNotFoundException
  • ReadOnlyException
  • RowNotInTableException
  • StrongTypingException
  • TypedDataSetGeneratorException
  • UpdateException
  • VersionNotFoundException

ConstraintException

制約を有効にできませんでした。行に入力できるのは、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' は既に存在します。」

InvalidConstraintException

InvalidConstraintException Class (System.Data) | Microsoft Learn

親テーブルに存在している子キーが必要

ForeignKeyConstraint ConstraintName には親テーブルに存在している子キー値 (***) が必要です。

DataSet dataSet = new DataSet();
DataTable tableA = dataSet.Tables.Add();
DataTable tableB = dataSet.Tables.Add();

DataColumn columnA = tableA.Columns.Add();
DataColumn columnB = tableB.Columns.Add();

DataRelation relation = dataSet.Relations.Add(columnA, columnB);

tableA.Rows.Add("1");
tableB.Rows.Add("1"); // ok

tableB.Rows.Add("2"); // InvalidConstraintException「ForeignKeyConstraint Relation1 には親テーブルに存在している子キー値 (2) が必要です。」

このときDataRowを先に追加していると、DataRelationを設定したときに「対応する親の値が指定されてない値があるため、この制約を有効にできません。」としてArgumentExceptionが投げられます。

tableB.Rows.Add("2");
DataRelation relation = dataSet.Relations.Add(columnA, columnB); // ArgumentException

子行が孤立する

制約がリレーションシップ Relation で適用され、この値を変更すると子行が孤立するため、変更できません。(Cannot make this change because constraints are enforced on relation Relation, and changing this value will strand child rows.)

DuplicateNameException

既に属している

'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

RowNotInTableException

この例外はDelete()またはDataRowCollection.Remove()で行が削除されているときに、以下のメソッドが呼ばれたときに投げられます。Remarks - RowNotInTableException Class (System.Data) | Microsoft Learn

  • DataRow.AcceptChanges()
  • DataRow.RejectChanges()
  • DataRow.GetParentRow()
  • DataRow.GetParentRows()

テーブルにない行で操作を実行できない

テーブルにない行でこの操作を実行することはできません。

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();

DataColumn columnA = tableA.Columns.Add();
DataColumn columnB = tableB.Columns.Add();

DataRelation relation = dataSet.Relations.Add(columnA, columnB);

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

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

IndexOutOfRangeException

コレクションに含まれていない行を除去しようとした場合などは、DataExceptionから派生していない例外が投げられます。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「指定された DataRow は現在の DataRowCollection ではありません。」

DeletedRowInaccessibleException

この例外は削除されている行の値を、以下のプロパティやメソッドで取得や設定しようとするときに投げられます。Remarks - DeletedRowInaccessibleException Class (System.Data) | Microsoft Learn

  • DataRow.Item[]
  • DataRow.ItemArray
  • DataRow.BeginEdit()

削除された行を通してアクセスできない

削除された行を通して、その行の情報にアクセスすることはできません。

DataTable table = new DataTable();
table.Columns.Add();

DataRow row = table.Rows.Add();
row.AcceptChanges();
row.Delete(); // RowState: Deleted


row[0] = 1; // DeletedRowInaccessibleexception「削除された行を通して、その行の情報にアクセスすることはできません。」
object data1 = row[0]; // DeletedRowInaccessibleexception

row.AcceptChanges(); // ok. RowState: Detached

row.RowError = "a"; // ok
string error = row.RowError; // ok

RowStateがDeletedならば、DataRow.GetChildRows()などでもこの例外が投げられます。

VersionNotFoundException

存在しない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 データがありません。」
Microsoft Learnから検索