none
DataTable 行削除 RRS feed

  • 質問

  • DataTableから一行削除し、一行追加したいです。

    Data.Rows[i].Delete();//3→3行(変わらない?)

    Data.Rows.Add(dat1, dat2, dat3, dat4);//3→4行

    String hoge = Data.Rows[i]["F1"].ToString();//ここで落ちないようにしたいです

    しかし↑の時点でDeletedRowInaccessibleExceptionとエラーになります。

    調べたところ、Delete()しても行自体は残っている(アクセスは出来ないが)らしいです。

    上記の処理を実現するにはどのようにすればよいうでしょうか?

     

     

    2010年3月31日 7:31

回答

  • DataTable.AcceptChanges メソッドを実行して、テーブルに対して行われたすべての変更をコミットするか、
    もしくは DataRow.RowState プロパティで行状態を調べ、DataRow.RowState = DataRowState.Deleted なら処理をスルーするようにします。

    DataRow.RowState プロパティ
    DataRowState 列挙体


    ひらぽん http://blogs.yahoo.co.jp/hilapon/
    2010年3月31日 8:02
    モデレータ
  • > 調べたところ、Delete()しても行自体は残っている(アクセスは出来ないが)らしいです。

    その通りです。DataRow.Delete メソッドは削除対象の行に Deleted という印をつけ
    るだけです。それがどのような感じかは、以下のページの「図 1 DataSet 内の更新
    イメージ」を見るとよく分かると思います。

    DB 設計者のための明解 ADO.NET 第 1 回
    http://msdn.microsoft.com/ja-jp/events/dd231281.aspx

    DataTable の行を削除するには DataRowCollection.Remove メソッドまたは RemoveAt
    メソッドを使用します。

    または、ひらぽんさんが書いておられるように、DataRow.Delete メソッドを実行した
    後でAcceptChanges メソッドを呼び出すという手段もあります。

    詳しくは以下のページが参考になると思います。

    DataRow の削除
    http://msdn.microsoft.com/ja-jp/library/03c7a3zb.aspx


    > 上記の処理を実現するにはどのようにすればよいうでしょうか?

    未検証ですが、Data.Rows.RemoveAt(i); としたら、Data.Rows[i]["F1"].ToString() で
    少なくとも例外はスローされないと思います。(i がどの行を指しているかにもよりますが)

    • 回答としてマーク sikake_chui 2010年4月1日 1:44
    • 回答としてマーク sikake_chui 2010年4月1日 1:44
    2010年3月31日 14:33

すべての返信

  • DataTable.AcceptChanges メソッドを実行して、テーブルに対して行われたすべての変更をコミットするか、
    もしくは DataRow.RowState プロパティで行状態を調べ、DataRow.RowState = DataRowState.Deleted なら処理をスルーするようにします。

    DataRow.RowState プロパティ
    DataRowState 列挙体


    ひらぽん http://blogs.yahoo.co.jp/hilapon/
    2010年3月31日 8:02
    モデレータ
  • > 調べたところ、Delete()しても行自体は残っている(アクセスは出来ないが)らしいです。

    その通りです。DataRow.Delete メソッドは削除対象の行に Deleted という印をつけ
    るだけです。それがどのような感じかは、以下のページの「図 1 DataSet 内の更新
    イメージ」を見るとよく分かると思います。

    DB 設計者のための明解 ADO.NET 第 1 回
    http://msdn.microsoft.com/ja-jp/events/dd231281.aspx

    DataTable の行を削除するには DataRowCollection.Remove メソッドまたは RemoveAt
    メソッドを使用します。

    または、ひらぽんさんが書いておられるように、DataRow.Delete メソッドを実行した
    後でAcceptChanges メソッドを呼び出すという手段もあります。

    詳しくは以下のページが参考になると思います。

    DataRow の削除
    http://msdn.microsoft.com/ja-jp/library/03c7a3zb.aspx


    > 上記の処理を実現するにはどのようにすればよいうでしょうか?

    未検証ですが、Data.Rows.RemoveAt(i); としたら、Data.Rows[i]["F1"].ToString() で
    少なくとも例外はスローされないと思います。(i がどの行を指しているかにもよりますが)

    • 回答としてマーク sikake_chui 2010年4月1日 1:44
    • 回答としてマーク sikake_chui 2010年4月1日 1:44
    2010年3月31日 14:33
  • ありがとうございます。

    なんだかDBテーブルのような使い方をするんですね。

    (だからData-Tableなのかな?)

    Data.Rows[i].Delete();

    Data.AcceptChanges();

    String hoge = Data.Rows[i]["F1"].ToString();

    で通りました。

     

    2010年4月1日 0:22
  • ありがとうございます。

    Data.Rows.RemoveAt(i); 

    で実現できました。

    今回はロールバックの必要が無い要件ですのでこちらを採用しました。

     

    2010年4月1日 1:43
  • sikake_chui さんが今後も「ロールバックの必要有無」で判断されるとよくないと思ったので、一言をと思ったら長くなりました。もし逆に混乱させてしまったらすみません。

    DataTable を利用することで、データ操作をその都度データベースに反映するのではなく、後で一括してデータベースに変更を反映することが簡単になります。これは非接続型では重要な機能です。
    そのために DataTable では、削除という操作を行った後も、それをデータベースに反映するまでは「削除されたこと」がわかるようになっています。(追加や変更についてもそれが後で調べられるようになっています。)
    これが Delete を行ってもすぐには削除されない理由になります。Delete の操作をロールバックすることが目的ではないのです。

    ただし、Delete の時点ですぐに削除される場合もあります。
    新しい行を追加してからデータベースに反映するまでに(正しくは AcceptChanges するまでに)Delete した場合は、後で「削除されたこと」がわかる必要はないため、すぐに削除されます。

    一方、Remove(または RemoveAt)メソッドを使うと実際にすぐに行が削除されますが、この場合は「削除されたこと」を後で調べることはできませんので、その必要がない場合に限定して Delete メソッドと適切に使い分ける必要があります。

    データベースに変更を反映した後であればもう変更有無を把握する必要はなくなりますので、その場合に AcceptChanges メソッドを使って反映済み状態にします。

    そのため、もしも sikake_chui さんのプログラムにデータベースの更新処理がある場合は、AcceptChanges するまでの変更操作や Remove した行はデータベースに反映されないことになります。
    その点、大丈夫でしょうか?
    ただのメモリ変数としての使用でしたら大丈夫ですが、Delete して残っているということはそれまでに AcceptChanges されているはずで、おそらくデータベース操作が絡んでいるのではと想像します。

    sikake_chui さん
    > Delete()しても行自体は残っている(アクセスは出来ないが)らしいです

    今回は必要性はないと思いますが、実際にはアクセス可能です。
    Data.Rows[i]["F1", DataRowVersion.Original] とすると、もともとの値にアクセスできます。

    それと念のために書きますけど、Delete して実際に行が削除されない場合は Rows[i] のインデックスはずれませんが、AcceptChanges や Remove などによって実際に行が削除されるとずれますので、書かれたコードでは、hoge に代入する値は次の行などのものになります。

    2010年4月1日 6:14
  • 今回はCSVをDBとしてDataTableを使用しました。

    今後CSVの代わりにSQLServerが導入されることを前提に作成しています。

    >後で一括して反映~

    一行のデ-タを更新する為に更新ボタン→対象行削除→対象行更新デ-タ追加→CSV書込み→更新ボタンを行っています。

    そういう意味では非接続型のメリットを殺してしまってるみたいですね。

    >追加や変更についてもそれが後で調べられるようになっています。

    今回の場合デストラクタ(入力画面Close)でDataTableが変更されていたら一括CSV書込みとかの方が良いのかも。

    でも更新ボタン押して実DBが更新されないというのはどうなんだろう?

     

    脱線しました。

    ロ-ルバックが目的でないということは理解できました、ありがとうございます。

     

     

     

     

     

    2010年4月1日 8:16
  • > そういう意味では非接続型のメリットを殺してしまってるみたいですね。

    アプリケーション仕様(または使い勝手)にもよるので、都度更新の方がよい場合もあると思います。

    > でも更新ボタン押して実DBが更新されないというのはどうなんだろう?

    そのあたりは難しいですね。
    ユーザーにとって解りにくいことは、トラブルにつながる可能性もありますからね。

    > ロ-ルバックが目的でないということは理解できました、ありがとうございます。

    長々と書きましたが、そこがお伝えしたいことでしたので良かったです。

    2010年4月1日 10:56