同じ値を設定しても DataTable が Modified になってしまうのを防ぐ方法

Entity Framework (+ LINQ) が主流になってからかなりの期間がたちますが*1、まだまだ 型付き DataSet や DataTable は使われていると思います。そんなときにちょっと役立つ Tips を紹介します。

ASP.NET の GridView を Excel のような形式で編集できるようにしている場合、ユーザが入力した値を DataTable に書き戻すという処理もしているのではないでしょうか。このとき、 DataRow のカラムに元と同じ値を単純に設定すると、 RowState (DataRowState) が Modified になってしまいます。 Unchanged のままにしたいがために、 1 つの列ごとに元の値と比較している人も多いのではないでしょうか。

実は、ちょっとした工夫でシンプルに各方法があります。あらかじめ以下のユーティリティ関数を定義しておきます。このメソッドは、 DataRow がオリジナルの値から変更されているかをチェックし、変更されていれば true を、変更されていなければ false を返します。

/// <summary>
/// 行がオリジナルから変更されているかチェック
/// </summary>
private bool IsChanged(DataRow row)
{
    foreach (DataColumn column in row.Table.Columns)
    {
        if (!row[column, DataRowVersion.Current].Equals(
            row[column, DataRowVersion.Original]))
            return true;
    }

    return false;
}

使用法は、以下のようになります。ユーザが入力した値を DataRow に全て代入した後、 IsChanged() を呼び出します。元の値から変更されていなければ、 AcceptChanges() を呼び出すことで RowState が Unchanged に戻ります。

foreach (DataRow row in table)
{
    // GridView などからユーザの入力内容を全て row に反映
    // このとき、元の値から変化しているかどうかは気にしない
    // row.VALUE1 = textBox1.Text;
    // row.VALUE2 = textBox2.Text;

    // 元の値から全く変化がなければ、 RowState を元の状態に戻す
    if (!IsChanged(row))
        row.AcceptChanges();
}

*1:個人的希望も含まれています ^^