DataTableのデータの行を表します。このクラスのインスタンスは、DataTable.Rows.Add()またはDataTable.NewRow()などから作成できます。
型 | プロパティ | 内容 |
---|---|---|
object | Item[DataColumn] | 指定のDataColumnに格納されているデータ |
object | Item[String] | 指定の名前の列に格納されているデータ |
object | Item[Int32] | 指定のインデックスの列に格納されているデータ |
object | Item[Int32, DataRowVersion] | 指定のインデックスの列に格納されている、指定のバージョンのデータ |
object[] | ItemArray | 行のすべての値 |
DataTable | Table | この行のスキーマがあるDataTable。これはこの行がDataTableのコレクションに属しているかは無関係であり、それを知りたくばRowStateがDetachedであるかどうかで判別する |
DataRowState | RowState | 行の状態 |
string | RowError | 行のカスタムエラー |
bool | HasErrors | trueならば、エラーが含まれている。個別の項目にエラーが含まれているか、RowErrorプロパティが空文字列ではないならば、trueとなる |
DataTableに含まれていないDataRow、つまりRowStateがDetachedの行を処理しようとすると、RowNotInTableExceptionが投げられます。
引数でDataRowVersionも指定することで、異なる状態の値を取得できます。DataRow.Item[String, DataRowVersion] Property (System.Data) | Microsoft Learn
それを指定しない場合は、Defaultの状態の値となります。this - DataRow.cs
Stringで列を指定するときは、大文字/小文字は区別されません。
RowStateの状態によっては、次の例外が投げられます。
列挙子 | 数値 | 意味 |
---|---|---|
Current | 512 | 現在の値 |
Original | 256 | 初期値
(最初に設定した値ではなく、編集前の値の意味。AcceptChanges()を呼ぶと、このOriginalがCurrentの値に更新される) |
Proposed | 1024 | 提案値 (proposed value)
(編集を確定する前の値) |
Default | 1536 | DataRowStateの値によって異なる
|
DataRowVersionは、次の状況で変更されます。Remarks - DataRowVersion Enum (System.Data) | Microsoft Learn
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.NewRow(); DataRowState state = row.RowState; // Detached row[0] = 1; table.Rows.Add(row); state = row.RowState; // Added object current, original, proposed; current = row[0, DataRowVersion.Current]; // "1" // original = row[0, DataRowVersion.Original]; // VersionNotFoundException // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException row.AcceptChanges(); state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException row.BeginEdit(); // 編集を開始する state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" proposed = row[0, DataRowVersion.Proposed]; // "1" row[0] = 2; // 値を操作する state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" proposed = row[0, DataRowVersion.Proposed]; // "2" row.EndEdit(); // 編集を終了する state = row.RowState; // Modified current = row[0, DataRowVersion.Current]; // "2" original = row[0, DataRowVersion.Original]; // "1" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException row[0] = 3; // 値を操作する state = row.RowState; // Modified row.AcceptChanges(); // 変更を確定する state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "3" original = row[0, DataRowVersion.Original]; // "3" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException row.Delete(); // 行を削除する state = row.RowState; // Deleted // current = row[0, DataRowVersion.Current]; // VersionNotFoundException original = row[0, DataRowVersion.Original]; // "3" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException // row[0] = 4; // DeletedRowInaccessibleException row.AcceptChanges(); // 変更を確定する state = row.RowState; // Detached // current = row[0, DataRowVersion.Current]; // VersionNotFoundException // original = row[0, DataRowVersion.Original]; // VersionNotFoundException // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException
列挙子 | 数値 | 意味 |
---|---|---|
Detached | 1 | 行は作成されているが、コレクションの一部ではない。これはコレクションへの追加前か除去後の状態 |
Unchanged | 2 | AcceptChanges()が呼ばれてから、行は変更されていない |
Added | 4 | 行はコレクションに追加されているが、AcceptChanges()は呼ばれていない |
Deleted | 8 | 行はDelete()で削除されているが、AcceptChanges()は呼ばれていない |
Modified | 16 | 行は変更されているが、AcceptChanges()は呼ばれていない |
AllowDBNullがtrueの列にはnullが格納されることがあります。しかしその値は実際にはnullとは異なるため、
row[column] == null
としても判定できず、
row[column] == DBNull.Value
のようにSystem.DBNullクラスのValueフィールドと比較する必要があります。これはConvertクラスのメソッドを用いて
Convert.IsDBNull(row[column])
とすることでも可能です。なお、このConvertクラスのDBNullフィールドは、DBNull.Value
です。
またはDataRowのIsNull()メソッドを用いて、
row.IsNull(column)
として判定する方法もあります。DataRow.IsNull Method (System.Data) | Microsoft Learn
DataTable table = new DataTable(); DataColumn column = table.Columns.Add(); DataRow row = table.Rows.Add(); row.SetField(column, DBNull.Value); bool r1 = row[column] == null; // false bool r2 = row[column] == DBNull.Value; // true bool r3 = Convert.IsDBNull(row[column]); // true bool r4 = row.IsNull(column); // true
未設定ならば、空文字列が返されます。未設定のときnullまたは空文字列を指定しても、それは設定されません。以降はnullを指定すると空文字列が、それ以外はその文字列が設定されます。DataRow.rowerror
個別の項目にエラーを設定するには、SetColumnError()を使用する。
エラーを変更しても、RowStateは変更されません。
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.Rows.Add("A"); row.AcceptChanges(); DataRowState state = row.RowState; // Unchanged row.RowError = "error"; state = row.RowState; // Unchanged row.SetColumnError(0, "error"); state = row.RowState; // Unchanged
メソッド | 機能 |
---|---|
GetChildRows(String) | DataRowの子の行を取得できる |
GetParentRow(String) | DataRowの、1つの親の行を取得できる |
GetParentRows(String) | DataRowの、複数の親の行を取得できる |
SetParentRow(DataRow) | DataRowに、親の行を設定できる |
HasVersion(DataRowVersion) | 指定のバージョンが存在するか確認できる |
IsNull(DataColumn) | 指定の列がnullを含むか確認できる |
BeginEdit() | 編集モードにできる |
CancelEdit() | 編集をキャンセルできる |
EndEdit() | 編集を終了できる |
AcceptChanges() | 最後にAcceptChanges()を呼んだ後の変更をコミットできる。EndEdit()が暗黙的に呼ばれ、編集モードが終わる
RowStateがAddedまたはModifiedならばUnchangedになり、Deletedならば行は除去される |
RejectChanges() | 最後にAcceptChanges()を呼んだ後の変更を拒否できる。CancelEdit()が暗黙的に呼ばれ、編集がキャンセルされる
RowStateがdeletedまたはmodifiedならばunchangedになり前の値に戻させる。またaddedならば行は除去される |
SetAdded() | RowStateを、Addedに変更できる。これを呼べるのはRowStateがUnchangedのときのみで、現在のデータが初期値に設定される |
SetModified() | RowStateを、Modifiedに変更できる。これを呼べるのはRowStateがUnchangedのときのみで、コミットしていないデータは初期値に戻される |
Delete() | RowStateを、Deletedに変更できる。RowStateがAddedならば除去されるが、そうでなければAcceptChanges()が呼ばれたときに除去される。 |
SetNull(DataColumn) | (protected) 指定の列を、null値に設定する。これはItemプロパティからDBNull.Valueを設定するのと同義 SetNull - DataRow.cs |
SetColumnError(DataColumn, String) | 列のエラーの説明を設定できる。エラーを消すには、nullまたは空文字列を設定する |
GetColumnError(DataColumn) | 列のエラーの説明を取得できる |
GetColumnsInError() | エラーのある列の配列を取得できる |
ClearErrors() | 行のエラーを消去できる。これにはRowErrorプロパティと、SetColumnError()で設定したエラーが含まれる |
メソッド | 機能 |
---|---|
Field<T>(DataRow, String) | 指定の列を、指定の型で取得できる |
SetField<T>(DataRow, String, T) | 指定の列に、新しい値を設定できる |
DataRelationが設定された、子の行を取得できます。
public System.Data.DataRow[] GetChildRows (string relationName);GetChildRows(String) - DataRow.GetChildRows Method (System.Data) | Microsoft Learn
DataRowVersionを省略すると、DataRowVersion.Defaultが指定されます。
子の行が存在しないときは、長さゼロの配列が返されます。
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"); DataRow[] childRows = rowA.GetChildRows(relation); DataRow childRow = childRows.Single(); bool equals = Object.ReferenceEquals(childRow, rowB); // true
削除された行の子の行を取得しようとすると、DeletedRowInaccessibleExceptionが投げられます。このような場合には、DataRowVersionを指定して取得します。
row.Delete();
// DataRow[] rows = row.GetChildRows(relation); // DeletedRowInaccessibleException
DataRow[] rows = row.GetChildRows(relation, DataRowVersion.Original);
内部ではIndex.GetRows()で列挙子が用いられているため、このメソッドを呼び出しているときに別スレッドから子となる行を操作すると、「コレクションが修正されました。列挙操作が実行されない可能性があります。」としてInvalidOperationExceptionが投げられます。
親の行を取得できます。
public System.Data.DataRow GetParentRow (string relationName);GetParentRow(String) - DataRow.GetParentRow Method (System.Data) | Microsoft Learn
DataRowVersionを省略すると、DataRowVersion.Defaultが指定されます。
DataRowのRowStateがDeletedのとき、GetParentRows()ではDeletedRowInaccessibleExceptionが投げられますが、このメソッドではnullが返されます。
DataRowの編集操作を開始できます。この編集モードではDataRowを操作してもイベントは発生しなくなります。
DataTable table = new DataTable(); table.Columns.Add(); table.Columns.Add(); table.RowChanged += (object sender, DataRowChangeEventArgs e) => { }; DataRow row1 = table.Rows.Add(); // RowChangedが発生し、そのe.actionは Add row1[0] = 1; // Change row1[1] = 2; // Change row1.AcceptChanges(); // Commit DataRow row2 = table.Rows.Add(); // Add row2.BeginEdit(); row2[0] = 1; // RowChangedは発生しない row2[1] = 2; row2.AcceptChanges(); // Change、Commitと RowChangedが2回発生する
DataTable table = new DataTable(); table.Columns.Add(); DataRow row = table.Rows.Add(1); DataRowState state = row.RowState; // Added object current, original, proposed; current = row[0, DataRowVersion.Current]; // "1" // original = row[0, DataRowVersion.Original]; // VersionNotFoundException // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException // Begin - Cancel row.BeginEdit(); state = row.RowState; // Added row[0] = 2; // state = row.RowState; // Added current = row[0, DataRowVersion.Current]; // "1" // original = row[0, DataRowVersion.Original]; // VersionNotFoundException proposed = row[0, DataRowVersion.Proposed]; // "2" row.CancelEdit(); state = row.RowState; // Added current = row[0, DataRowVersion.Current]; // "1" // original = row[0, DataRowVersion.Original]; // VersionNotFoundException // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException row.AcceptChanges(); state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException // Begin - Cancel row.BeginEdit(); state = row.RowState; // Unchanged row[0] = 2; // state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" proposed = row[0, DataRowVersion.Proposed]; // "2" row.CancelEdit(); state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException // Begin - End row.BeginEdit(); state = row.RowState; // Unchanged row[0] = 2; // state = row.RowState; // Unchanged current = row[0, DataRowVersion.Current]; // "1" original = row[0, DataRowVersion.Original]; // "1" proposed = row[0, DataRowVersion.Proposed]; // "2" row.EndEdit(); state = row.RowState; // Modified current = row[0, DataRowVersion.Current]; // "2" original = row[0, DataRowVersion.Original]; // "1" // proposed = row[0, DataRowVersion.Proposed]; // VersionNotFoundException
最後にAcceptChanges()を呼んだ後の変更をコミットできます。
public void AcceptChanges ();DataRow.AcceptChanges Method (System.Data) | Microsoft Learn
既定では子の行へは作用しません。これはForeignKeyConstraint.AcceptRejectRuleをCascadeに設定することで変更できます。AcceptChanges and RejectChanges - ADO.NET | Microsoft Learn
public void Delete ();DataRow.Delete Method (System.Data) | Microsoft Learn
Delete()の呼び出し時にRowStateがAddedならばDataTable.Rowsから除去されDetachedとなりますが、そうでなければDeletedとなりAcceptChanges()が呼ばれたときに除去されDetachedとなります。これを無条件に実行したいならば、DataRowCollection.Remove()を呼びます。
DataTable table = new DataTable(); DataRow row1 = table.Rows.Add(); Console.WriteLine($"{row1.RowState} : {table.Rows.Count}"); // Added : 1 row1.Delete(); // DataTable.Rowsから除去される Console.WriteLine($"{row1.RowState} : {table.Rows.Count}"); // Detached : 0 DataRow row2 = table.Rows.Add(); row2.AcceptChanges(); Console.WriteLine($"{row2.RowState} : {table.Rows.Count}"); // Unchanged : 1 row2.Delete(); // 削除済みとマークされるが、DataTable.Rowsに残っている Console.WriteLine($"{row2.RowState} : {table.Rows.Count}"); // Deleted : 1 row2.AcceptChanges(); // ここでDataTable.Rowsから除去される Console.WriteLine($"{row2.RowState} : {table.Rows.Count}"); // Detached : 0
RowStateがDeletedとなった状態からは、RejectChanges()により呼び出し前の状態に戻せます。
DataRow row3 = table.Rows.Add(); row3.AcceptChanges(); Console.WriteLine($"{row3.RowState} : {table.Rows.Count}"); // Unchanged : 1 row3.Delete(); Console.WriteLine($"{row3.RowState} : {table.Rows.Count}"); // Deleted : 1 row3.RejectChanges(); // Delete()の呼び出し前に戻せる Console.WriteLine($"{row3.RowState} : {table.Rows.Count}"); // Unchanged : 1 row3.Delete(); // Deleted row3.AcceptChanges(); // Detached row3.RejectChanges(); // Detached. もう戻らない
Delete()はそのDataRowが含まれるDataRowCollectionの状態を変更するため、そのコレクションのforeachループ内から呼んではなりません。Remarks - DataRow.Delete Method (System.Data) | Microsoft Learn
DataTable table = new DataTable();
table.Rows.Add();
table.Rows.Add();
foreach (DataRow row in table.Rows) // 2回目のループで、InvalidOperationException「コレクションが修正されました。列挙操作が実行されない可能性があります。」が投げられる
{
row.Delete();
}
Relationが設定された子テーブルがあるならば、その子行へも作用します。
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(); DataRowState stateA = rowA.RowState; // Detached DataRowState stateB = rowB.RowState; // Detached
ただしForeignKeyConstraint.DeleteRuleが既定から変更されているときには、その設定に従います。
... relation.ChildKeyConstraint.DeleteRule = Rule.SetDefault; rowA.AcceptChanges(); rowB.AcceptChanges(); rowA.Delete(); DataRowState stateA = rowA.RowState; // Deleted DataRowState stateB = rowB.RowState; // Modified
指定の列を、指定の型で取得できます。このメソッドはSystem.Data.DataSetExtensionsで定義されているため、利用するにはこれを参照に追加する必要があります。
public static T Field<T> ( this System.Data.DataRow row, string columnName );Field<T>(DataRow, String) - DataRowExtensions.Field Method (System.Data) | Microsoft Learn
このメソッドは次のように実装されています。
public static T Field<T>(this DataRow row, string columnName) {
DataSetUtil.CheckArgumentNull(row, "row"); // rowがnullならば、ArgumentNullExceptionが投げられる
return UnboxT<T>.Unbox(row[columnName]);
}
Field - DataRowExtensions.cs
指定の型への変換に失敗したときには、InvalidCastExceptionが投げられます。これは列のデータがnullのとき、指定の型がNULL許容型ではない場合も同様です。この、データがnullのときの挙動が、Item[]プロパティと異なります。
DataTable table = new DataTable(); table.Columns.Add("col1", typeof(object)); table.Columns.Add("col2", typeof(int)); DataRow row = table.NewRow(); // 指定の列のデータがnullのとき object val1 = row["col1"]; // DBNull が返される object val2 = row["col2"]; // DBNull が返される object val3 = row.Field<object>("col1"); // null が返される object val4 = row.Field<int>("col2"); // InvalidCastException が投げられる
列の型 | ||
---|---|---|
object | int | |
Item[] | DBNull | DBNull |
Field<T>() | null | InvalidCastException |
列をDataColumnで指定するオーバーロードでは、それにnullを指定すると「'column' 引数を Null にすることはできません。」としてArgumentNullExceptionが投げられます。
DataTable table = new DataTable("table"); DataColumn col1 = table.Columns.Add("col1", typeof(object)); DataColumn col2 = new DataColumn("col2"); DataColumn col3 = null; DataRow row = table.NewRow(); object val1 = row[col1]; // DBNull object val2 = row[col2]; // ArgumentException「列 'col2' はテーブル table に属していません。」 object val3 = row[col3]; // ArgumentNullException「'column' 引数を Null にすることはできません。」 object val4 = row.Field<object>(col1); // null object val5 = row.Field<object>(col2); // ArgumentException「列 'col2' はテーブル table に属していません。」 object val6 = row.Field<object>(col3); // ArgumentNullException「'column' 引数を Null にすることはできません。」
指定の列に、新しい値を設定できます。
public static void SetField<T> ( this System.Data.DataRow row, string columnName, T value );SetField<T>(DataRow, String, T) - DataRowExtensions.SetField Method (System.Data) | Microsoft Learn
DataTable table = new DataTable(); table.Columns.Add("col1", typeof(object)); table.Columns.Add("col2", typeof(int)); DataRow row = table.NewRow(); // col1 row.SetField("col1", DBNull.Value); // OK row.SetField<object>("col1", null); // OK row.SetField<int>("col1", 1); // OK row["col1"] = DBNull.Value; // OK row["col1"] = null; // OK // col2 row.SetField("col2", DBNull.Value); // OK row.SetField<object>("col2", null); // OK row.SetField<string>("col2", "a"); // FormatException「入力文字列の形式が正しくありません。」 row["col2"] = DBNull.Value; // OK row["col2"] = null; // ArgumentException「Column 'col2' を null に設定できません。DBNull を使用してください。」
このメソッドは次のように実装されています。
public static void SetField<T>(this DataRow row, string columnName, T value) { DataSetUtil.CheckArgumentNull(row, "row"); row[columnName] = (object)value ?? DBNull.Value; }SetField - DataRowExtensions.cs
そのためnullを指定するとDBNull.Valueが設定されます。
DataTable table = new DataTable(); DataColumn col1 = table.Columns.Add("", typeof(object)); DataRow row = table.NewRow(); row.SetField(col1, DBNull.Value); object v1 = row.Field<object>(col1); // null object v2 = row[col1]; // DBNull row.SetField<object>(col1, null); object v3 = row.Field<object>(col1); // null object v4 = row[col1]; // DBNull
DataRowにはGetChanges()が実装されていないため、変更されたデータは独自に取得する必要があります。.net - DataRow.GetChanges() or equivalent - Stack Overflow
// 変更されたデータを含む、DataTableのコピーを取得する DataTable changedTable = dataTable.GetChanges(); // 変更されたデータを含む行を、1行ずつ確認する foreach (DataRow row in changedTable.Rows) { // すべての列のデータを、1つずつ確認する foreach (DataColumn column in changedTable.Columns) { object original = row[column, DataRowVersion.Original]; object current = row[column, DataRowVersion.Current]; if (!object.Equals(original, current)) { // row[column]が変更されている } } }