LoginSignup
7
10

More than 5 years have passed since last update.

.NET の DataTable の行の編集状態(RowState)の変化についてのまとめ

Last updated at Posted at 2018-08-02

概要

.NET の DataTable は、DB を更新しやすいように、トランザクションみたいな概念と、各行の状態(編集あり/編集なし/追加/削除)を保持しています。

トランザクションみたいな概念

  • AcceptChange() で全ての DataRow の RowState が「修正なし」になる。
  • それ以降に 追加/修正/削除をした場合は、RowState の状態が対応する値に変化する。
  • AcceptChange() をすると、「削除」行は消え、「追加」「修正」行は「修正なし」になる。
  • RejectChange() をすると、前回、AcceptChange() した状態に戻る。(※一部例外あり)

RowState

RowState 状態 補足
Detached 未追加 DataRowを定義したけどDataTableにAddされていない。
Unchanged 編集なし 編集なし。
Added 追加 Addedの行を削除すると行そのものが消える。
Modified 編集あり 編集あり
Deleted 削除 行としては存在する。AcceptChanges()で消える。

動作確認

実行ソース(C#)

static void Main(string[] args)
{
  // data
  var data = new DataTable();
  data.Columns.Add("ID");
  for (int i = 0; i < 3; i++)
  {
    data.Rows.Add(i);
  }
  data.AcceptChanges();

  Console.WriteLine("--------------------");
  foreach (DataRow row in data.Rows)
  {
    Console.WriteLine($"ID:{row["ID"]},RowState={row.RowState}");
  }

  // 追加
  var add = data.NewRow();    // add.RowState:DataRowState.Detached
  add["ID"] = 3;
  data.Rows.Add(add);         // add.RowState:DataRowState.Added

  // 修正
  var mod = data.Rows[0];     // mod.RowState:DataRowState.Unchanged
  mod["ID"] = 9;              // mod.RowState:DataRowState.Modified

  // 削除
  // ・削除された行として存在する。
  var del = data.Rows[1];    // del.RowState:DataRowState.Unchanged
  del.Delete();              // del.RowState:DataRowState.Deleted

  // 除外
  // ・DataTableから除外される。
  // ・data.RejectChanges();しても、dataから除外されたままになる。
  var rmv = data.Rows[2];    // rmv.RowState:DataRowState.Unchanged
  data.Rows.Remove(rmv);     // rmv.RowState:DataRowState.Detached

  Console.WriteLine("--------------------");
  foreach (DataRow row in data.Rows)
  {
    if (row.RowState == DataRowState.Deleted)
    {
      // 削除された行の値をアクセスしようとする例外が発生する。
      // →DataRowVersion.Original を付けて、削除前の状態の値を取得する。
      Console.WriteLine($"ID:{row["ID", DataRowVersion.Original]},RowState={row.RowState}");
    }
    else
    {
      Console.WriteLine($"ID:{row["ID"]},RowState={row.RowState}");
    }
  }

  // data.AcceptChanges();
  // data.RejectChanges();
  Console.WriteLine("--------------------");
  foreach (DataRow row in data.Rows)
  {
    Console.WriteLine($"ID:{row["ID"]},RowState={row.RowState}");
  }
}

出力結果

--------------------
ID:0,RowState=Unchanged
ID:1,RowState=Unchanged
ID:2,RowState=Unchanged
--------------------
ID:9,RowState=Modified
ID:1,RowState=Deleted
ID:3,RowState=Added

【data.AcceptChanges(); の場合】
--------------------
ID:9,RowState=Unchanged
ID:3,RowState=Unchanged

【data.RejectChanges(); の場合】
--------------------
ID:0,RowState=Unchanged
ID:1,RowState=Unchanged

補足

編集後記

動作を理解していないと思わぬところで Deleted データにアクセスしようとして例外が発生したり、更新対象を正しく取得できなくなってしまいます。
DBのトランザクション管理と同様に、どのタイミングで AcceptChanges(), RejectChanges() するかは、プロジェクトで徹底させないとえらい目に会います。

7
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
10