C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

DBのレコード追加 /ぽんた (19/09/10(Tue) 14:57) #92306
Re[1]: DBのレコード追加 /魔界の仮面弁士 (19/09/10(Tue) 15:57) #92314
│└ Re[2]: DBのレコード追加 /ぽんた (19/09/10(Tue) 16:06) #92315
│  └ Re[3]: DBのレコード追加 /魔界の仮面弁士 (19/09/10(Tue) 16:12) #92317
Re[1]: DBのレコード追加 /WebSurfer (19/09/10(Tue) 15:31) #92311


親記事 / ▼[ 92314 ] ▼[ 92311 ]
■92306 / 親階層)  DBのレコード追加
□投稿者/ ぽんた (1回)-(2019/09/10(Tue) 14:57:48)

分類:[.NET 全般] 

VisualStudio2017のウィンドウズアプリケーション、vb.netを使用しています。

データセットからDBを更新する処理で、
SQLのINSERT文でExecuteNonQueryメソッドを使いレコードを追加したのですが、
連続で追加するときに、一度データセットでAcceptChangesメソッドを実行しないとエラーになります。

なぜAcceptChangesメソッドを使う必要があるのでしょうか?
DataRow.RowStateプロパティのAdded行というのが関係しているのかと思うのですが、
そのあたりが、よく理解できていないので、合わせて説明していただきたいです。

回答よろしくお願いします
[ □ Tree ] 返信 編集キー/

▲[ 92306 ] / ▼[ 92315 ]
■92314 / 1階層)  Re[1]: DBのレコード追加
□投稿者/ 魔界の仮面弁士 (2368回)-(2019/09/10(Tue) 15:57:17)
No92306 (ぽんた さん) に返信
> なぜAcceptChangesメソッドを使う必要があるのでしょうか?
> DataRow.RowStateプロパティのAdded行というのが関係しているのかと思うのですが、
> そのあたりが、よく理解できていないので、合わせて説明していただきたいです。

RowState プロパティは、下記の 5 つの状態を意味します。
 Detached … DataTable に割り当てられていない行
 Unchanged … 更新されていない行
 Added … 新規追加された行
 Delted … 削除された行
 Modified … 更新された行

これにより、データベースに書き戻す必要があるかどうか、そして
書き戻す場合に InsertCommand/DeleteCommand/UpdateCommand のいずれの
クエリーを呼び出すかが判定されます。


また、AcceptChanges メソッドを呼び出すと、これらの状態が確定されて、
各行が以下のように変化します。
 Detached → Detached (影響を受けない)
 Unchanged → Unchanged (影響を受けない)
 Added → Unchanged (追加行が確定され、未編集行になる)※Originalが消え、Current のみになる
 Delted → Detached (削除処理が確定され、DataTable.Rows から取り除かれる)
 Modified → Unchanged (編集行が確定され、未編集行になる)※Current の内容が Original の値で置き換えられる

一方、RejectChanges() メソッドの場合には、編集前の状態に戻されれます。
 Detached → Detached (影響を受けない)
 Unchanged → Unchanged (影響を受けない)
 Added → Detached (追加処理がキャンセルされ、DataTable.Rows に未割当の状態に戻る)
 Delted → Unchanged (削除処理がキャンセルされ、未編集行に戻る)
 Modified → Unchanged (編集行がキャンセルされ、未編集行に戻る)※Originalが消え、Current のみになる


Sub Main()
 Dim ds As New DataSet()
 Dim tbl As DataTable = ds.Tables.Add("TBL")
 tbl.Columns.Add("COL1")

 '3 行のデータを登録して AcceptChanges しておく
 Dim row0 As DataRow = tbl.Rows.Add("0行目")
 Dim row1 As DataRow = tbl.Rows.Add("1行目")
 Dim row2 As DataRow = tbl.Rows.Add("2行目")
 ds.AcceptChanges()

 '0行目は削除
 '1行目は編集
 '2行目は何もしない
 '3行目に新規行
 row0.Delete()
 row1("COL1") = "編集"
 Dim row3 As DataRow = tbl.Rows.Add("3行目")

 '未割当の行
 Dim newRow As DataRow = tbl.NewRow()
 newRow("COL1") = "初期値"

 Console.WriteLine("=== RowState ===")
 For r = 0 To tbl.Rows.Count - 1
  Console.WriteLine("{0}行目の RowState = {1}", r, tbl.Rows(r).RowState)
 Next
 Console.WriteLine("未割当行の RowState = {0}", newRow.RowState)

 Console.WriteLine("=== DataRowVersion ===")
 Console.WriteLine("0行目の削除前の値=`{0}`", tbl.Rows(0)("COL1", DataRowVersion.Original))
 Console.WriteLine("1行目の編集前の値=`{0}`", tbl.Rows(1)("COL1", DataRowVersion.Original))
 Console.WriteLine("1行目の今現在の値=`{0}`", tbl.Rows(1)("COL1", DataRowVersion.Current))
 Console.WriteLine("2行目の編集前の値=`{0}`", tbl.Rows(2)("COL1", DataRowVersion.Original))
 Console.WriteLine("2行目の今現在の値=`{0}`", tbl.Rows(2)("COL1", DataRowVersion.Current))
 Console.WriteLine("3行目の今現在の値=`{0}`", tbl.Rows(3)("COL1", DataRowVersion.Current))
 Console.WriteLine("未割当行の 現在値=`{0}`", newRow("COL1", DataRowVersion.Proposed))

 Console.WriteLine("=== AcceptChanges 後の RowState ===")
 ds.AcceptChanges()
 For r = 0 To tbl.Rows.Count - 1
  Console.WriteLine("現{0}行目の RowState = {1}", r, tbl.Rows(r).RowState)
 Next
 Console.WriteLine("-----")
 Console.WriteLine("旧0行目の RowState = {0}", row0.RowState)
 Console.WriteLine("旧1行目の RowState = {0}", row1.RowState)
 Console.WriteLine("旧2行目の RowState = {0}", row2.RowState)
 Console.WriteLine("旧3行目の RowState = {0}", row3.RowState)

 Console.ReadLine()
End Sub
[ 親 92306 / □ Tree ] 返信 編集キー/

▲[ 92314 ] / ▼[ 92317 ]
■92315 / 2階層)  Re[2]: DBのレコード追加
□投稿者/ ぽんた (2回)-(2019/09/10(Tue) 16:06:37)
No92314 (魔界の仮面弁士 さん) に返信
> ■No92306 (ぽんた さん) に返信
>>なぜAcceptChangesメソッドを使う必要があるのでしょうか?
>>DataRow.RowStateプロパティのAdded行というのが関係しているのかと思うのですが、
>>そのあたりが、よく理解できていないので、合わせて説明していただきたいです。
>
> RowState プロパティは、下記の 5 つの状態を意味します。
>  Detached … DataTable に割り当てられていない行
>  Unchanged … 更新されていない行
>  Added … 新規追加された行
>  Delted … 削除された行
>  Modified … 更新された行
>
> これにより、データベースに書き戻す必要があるかどうか、そして
> 書き戻す場合に InsertCommand/DeleteCommand/UpdateCommand のいずれの
> クエリーを呼び出すかが判定されます。
>
>
> また、AcceptChanges メソッドを呼び出すと、これらの状態が確定されて、
> 各行が以下のように変化します。
>  Detached → Detached (影響を受けない)
>  Unchanged → Unchanged (影響を受けない)
>  Added → Unchanged (追加行が確定され、未編集行になる)※Originalが消え、Current のみになる
>  Delted → Detached (削除処理が確定され、DataTable.Rows から取り除かれる)
>  Modified → Unchanged (編集行が確定され、未編集行になる)※Current の内容が Original の値で置き換えられる
>
> 一方、RejectChanges() メソッドの場合には、編集前の状態に戻されれます。
>  Detached → Detached (影響を受けない)
>  Unchanged → Unchanged (影響を受けない)
>  Added → Detached (追加処理がキャンセルされ、DataTable.Rows に未割当の状態に戻る)
>  Delted → Unchanged (削除処理がキャンセルされ、未編集行に戻る)
>  Modified → Unchanged (編集行がキャンセルされ、未編集行に戻る)※Originalが消え、Current のみになる
>
>
> Sub Main()
>  Dim ds As New DataSet()
>  Dim tbl As DataTable = ds.Tables.Add("TBL")
>  tbl.Columns.Add("COL1")
>
>  '3 行のデータを登録して AcceptChanges しておく
>  Dim row0 As DataRow = tbl.Rows.Add("0行目")
>  Dim row1 As DataRow = tbl.Rows.Add("1行目")
>  Dim row2 As DataRow = tbl.Rows.Add("2行目")
>  ds.AcceptChanges()
>
>  '0行目は削除
>  '1行目は編集
>  '2行目は何もしない
>  '3行目に新規行
>  row0.Delete()
>  row1("COL1") = "編集"
>  Dim row3 As DataRow = tbl.Rows.Add("3行目")
>
>  '未割当の行
>  Dim newRow As DataRow = tbl.NewRow()
>  newRow("COL1") = "初期値"
>
>  Console.WriteLine("=== RowState ===")
>  For r = 0 To tbl.Rows.Count - 1
>   Console.WriteLine("{0}行目の RowState = {1}", r, tbl.Rows(r).RowState)
>  Next
>  Console.WriteLine("未割当行の RowState = {0}", newRow.RowState)
>
>  Console.WriteLine("=== DataRowVersion ===")
>  Console.WriteLine("0行目の削除前の値=`{0}`", tbl.Rows(0)("COL1", DataRowVersion.Original))
>  Console.WriteLine("1行目の編集前の値=`{0}`", tbl.Rows(1)("COL1", DataRowVersion.Original))
>  Console.WriteLine("1行目の今現在の値=`{0}`", tbl.Rows(1)("COL1", DataRowVersion.Current))
>  Console.WriteLine("2行目の編集前の値=`{0}`", tbl.Rows(2)("COL1", DataRowVersion.Original))
>  Console.WriteLine("2行目の今現在の値=`{0}`", tbl.Rows(2)("COL1", DataRowVersion.Current))
>  Console.WriteLine("3行目の今現在の値=`{0}`", tbl.Rows(3)("COL1", DataRowVersion.Current))
>  Console.WriteLine("未割当行の 現在値=`{0}`", newRow("COL1", DataRowVersion.Proposed))
>
>  Console.WriteLine("=== AcceptChanges 後の RowState ===")
>  ds.AcceptChanges()
>  For r = 0 To tbl.Rows.Count - 1
>   Console.WriteLine("現{0}行目の RowState = {1}", r, tbl.Rows(r).RowState)
>  Next
>  Console.WriteLine("-----")
>  Console.WriteLine("旧0行目の RowState = {0}", row0.RowState)
>  Console.WriteLine("旧1行目の RowState = {0}", row1.RowState)
>  Console.WriteLine("旧2行目の RowState = {0}", row2.RowState)
>  Console.WriteLine("旧3行目の RowState = {0}", row3.RowState)
>
>  Console.ReadLine()
> End Sub


返信ありがとうございます。
おそらく私はaddをしたあと、AcceptChanges メソッドせずにaddしてエラーになるのですが、
これがどういう理由でエラーになるのかがわかりません。
なぜなのでしょうか?
[ 親 92306 / □ Tree ] 返信 編集キー/

▲[ 92315 ] / 返信無し
■92317 / 3階層)  Re[3]: DBのレコード追加
□投稿者/ 魔界の仮面弁士 (2370回)-(2019/09/10(Tue) 16:12:42)
引用は適切に。無駄な全文引用は避けてください。

また、掲示板への返信欄に
 『半角カナは使用しないでください。文字化けの原因になります。』
という注意書きがあったかと思います。次回以降、御配慮ください。


No92315 (ぽんた さん) に返信
> おそらく私はaddをしたあと、AcceptChanges メソッドせずにaddしてエラーになるのですが、
何のエラーになったのかは、例外メッセージに記述されていませんか?

> これがどういう理由でエラーになるのかがわかりません。
> なぜなのでしょうか?
たとえば、PrimaryKey などの制約違反に陥っている可能性がありますね。
[ 親 92306 / □ Tree ] 返信 編集キー/

▲[ 92306 ] / 返信無し
■92311 / 1階層)  Re[1]: DBのレコード追加
□投稿者/ WebSurfer (1904回)-(2019/09/10(Tue) 15:31:43)
No92306 (ぽんた さん) に返信

何を作っているのか(Windows Forms? WPF? ASP.NET Web Forms? その他?)と DataSet をどの
ように使っているのかの説明がないと想像で答えざるとえなくて、想像が間違っていると混乱を
招くだけということになりそうですが・・・

たぶん Windows Forms アプリであろうと想像して。

> データセットからDBを更新する処理で、
> SQLのINSERT文でExecuteNonQueryメソッドを使いレコードを追加したのですが、
> 連続で追加するときに、一度データセットでAcceptChangesメソッドを実行しないとエラーになります。

普通の DataSet の使い方をしているのであればそういうことにはならないはずです。

以下の記事の「非接続型のデータ更新」のセクションの図1と図2を見てください。

DB 設計者のための明解 ADO.NET 第 1 回
https://docs.microsoft.com/ja-jp/previous-versions/cc482903(v=msdn.10)

「SQLのINSERT文でExecuteNonQueryメソッドを使いレコードを追加」ということは必要ないこと
が理解いただけるでしょうか?


DataGridView などを UI として非接続型のデータ更新を行う場合は、

DataGridview ⇔ BindingSource/BindingNavigator ⇔ DataSet/DataTable ⇔ DataAdapter⇔ DB

・・・と言う構造にするのが普通です。

そのような構造にすれば、ユーザーが DataGridView を操作した結果は紹介した記事の図1にあ
るように DataSet / DataTable に反映されます。もちろん追加の結果もです。

編集作業が終了後、ユーザーが DataAdapter に Update メソッドをかければ、図2のように
DataAdapter から SQL が自動発行され、SQL Server のテーブルが更新されます。

DB が SQL Server の場合ですが、以下のチュートリアル、

10 行でズバリ !! 非接続型のデータ アクセス (ADO.NET) (C#)
https://code.msdn.microsoft.com/windowsdesktop/10-ADONET-C-cbfe7688

・・・のように Visual Studio のデータソース構成ウィザードを利用して型付 DataSet +
TableAdapter を作って、それを利用してアプリを作ると、上に書いた、

DataGridview ⇔ BindingSource/BindingNavigator ⇔ DataSet/DataTable ⇔ DataAdapter⇔ DB

・・・と言う構造、すなわち以下のページの図のような構造のアプリが、ほとんど自分で
コードを書くこと無しに作れます。

Windows フォーム アプリケーションでのデータへの接続
https://docs.microsoft.com/ja-jp/previous-versions/wxt2cwcc(v=vs.120)

上に紹介したチュートリアルは 2 つのテーブルを階層更新するために少々複雑になってい
ますが、単一テーブルですともっと簡単で、操作に慣れると以下のようなアプリが 5 分も
かからず作れるはずです。

自力で一からコードを書く場合のような種々の問題に悩むことはなくなり、開発工数は
激減するはずです。保守工数も減るはずです。

興味があればお試しください。
[ 親 92306 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -