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

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

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

Re[1]: データグリッド内の更新


(過去ログ 120 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■72169 / inTopicNo.1)  データグリッド内の更新
  
□投稿者/ ロギー (3回)-(2014/05/22(Thu) 17:02:40)

分類:[.NET 全般] 

2014/05/22(Thu) 17:27:23 編集(投稿者)
度々質問させて頂きたいのですが、

只今access内のデータをデータグリッドビューに表示が出来ている状態で。
そこから項目内の変更をしたい場合の更新処理のコーディングで行き詰っています。

サイトで調べましたが、理解まで至りません。
VB と Accessでのやりとりですが、
検索でよくVBAの方がヒットしてしまい、こんがらがってます。


表示した時の処理での共通する部分とかがあるのでしょうか。
(イベント発生させる度にまたDBを呼び出す処理等)


変更をしたら更新のボタンを押した後にデータの中身が更新される処理を想定しています。


ご教授願います。



Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        '接続用変数の定義
        Dim OLEDBCon As OleDb.OleDbConnection = New OleDb.OleDbConnection
        Dim OLEDA As OleDb.OleDbDataAdapter
        Dim OLEDS As DataSet = New DataSet("TABLEDATA")
        Dim strSQL As String


        OLEDBCon.ConnectionString = _
          "Provider=Microsoft.Jet.OLEDB.4.0;" & _
          "Data Source= path" & _
          "Persist Security Info=False"

        'SQL構文を作成
        strSQL = "select * from Test"

        'SQL文を作成
        OLEDA = New OleDb.OleDbDataAdapter(strSQL, OLEDBCon)

        

        Try
            'データセットにデータを格納
            OLEDA.Fill(OLEDS, "Test")

            'データグリッドビューのデータソースを設定
            DataGridView1.DataSource = OLEDS.Tables("Test")

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try

        'セルの値を編集
        DataGridView1.ReadOnly = False

    End Sub

End Class

引用返信 編集キー/
■72171 / inTopicNo.2)  Re[1]: データグリッド内の更新
□投稿者/ 魔界の仮面弁士 (17回)-(2014/05/22(Thu) 18:32:19)
No72169 (ロギー さん) に返信
> データグリッド内の更新
> データグリッドビューに表示が出来ている状態で

System.Windows.Forms.DataGrid「データグリッド」と
System.Windows.Forms.DataGridView「データグリッドビュー」は
まったく別のコントロールですが、今回は、
DataGridView に関してという認識でよろしいでしょうか。


> "Data Source= path" & _
セミコロンが抜けていませんか?

『"Data Source=" & path & ";" & _』や
『"Data Source=path.mdb;" & _』など。


> 'データセットにデータを格納
> OLEDA.Fill(OLEDS, "Test")

上記により、データベースの内容が DataSet に格納されますね。(注1)
OleDbDataAdapter は、データベースと DataSet の仲介役を務めるクラスです。


> 'データグリッドビューのデータソースを設定
> DataGridView1.DataSource = OLEDS.Tables("Test")

これが、DataSet を DataGridView に割り当てたところですよね。

この後、DataGridView を編集すると、その編集結果は
DataSet 内にも反映されます。(注2)


さて、本題の「DataSet の内容をデータベースに書き戻す」方法ですが、
これは、先ほど用いた OleDbDataAdapter を利用することになります。

OleDbDataAdapter の Update メソッドに、編集された DataSet を
渡すことで、編集結果がデータベースに伝えられます。


たとえば、このような手順です。
http://blog.livedoor.jp/akf0/archives/51536291.html

上記は SQL Server が相手なので、SqlCommand や SqlDataAdapter が使われていますが、
今回は Access が相手なので、OleDbCommand や OleDbDataAdapter に置き換えれば OK です。



--
(注1) Visual Basic のコードエディタに『adoaccess』と書いてタブキーを押すと、
mdb ファイルからデータを読み取るサンプルコードが挿入されます。
(『?』と書いてタブキーを押して、一覧から選んでも可)

(注2)データを「編集中」の場合、その未確定の値はまだ DataSet には
記載されていません。入力中の値も確定させるのであれば、更新処理の前に
EndEdit メソッドを呼び出しておきましょう。
引用返信 編集キー/
■72174 / inTopicNo.3)  Re[1]: データグリッド内の更新
□投稿者/ WebSurfer (263回)-(2014/05/22(Thu) 20:10:55)
No72169 (ロギー さん) に返信

魔界の仮面弁士さんが書かれているように、 基本は DataSet と DataAdapter を利用してコ
ードを書くことですが、Visual Studio のデータソース構成ウィザード等を使って自分ではコ
ードを一行も書かずにアプリを作るアプローチを紹介しておきます。

ウィザードを使っても、基本は DataSet と DataAdapter です。以下のページの図1と図2を
見るとその概略が理解できると思います。ここが理解できているのといないのとでは、今後の
勉強のはかどり方に大きな違いが出てきますので、まずこれをよく見て理解してください。

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

Visual Studio のデータソース構成ウィザードを使うと、DataSet と DataAdapter を拡張し
た型付 DataSet と TableAdapter を自動生成して、以下のページの図の構成のアプリを自動
的に作ってくれます。

Windows フォーム アプリケーションでのデータへの接続
http://msdn.microsoft.com/ja-jp/library/wxt2cwcc(v=vs.110).aspx

Part6 .NETで,データベース・プログラムはこう作る
TableAdapterクラスがカギを握る
http://itpro.nikkeibp.co.jp/article/COLUMN/20070320/265659/

その作り方の具体的なチュートリアルは、以下のページが参考になると思います。

10 行でズバリ !! 非接続型のデータ アクセス (ADO.NET) (VB)
http://code.msdn.microsoft.com/10-ADONET-VB-1c64942f/

上のチュートリアルは SQL Server を使った場合の例ですが、Access でも基本は同じです。
2 つのテーブルを対象にしていますが、当然テーブルが一つならもっと簡単で 10 分もあれば
アプリが完成すると思います。

プロバイダの制約で、オートナンバーの列があると SQL Server の場合よりは処理がちょっと
面倒ですが、以下のようにして対応できます。

Access の更新
http://surferonwww.info/BlogEngine/post/2010/09/04/Updating-Access.aspx

ウィザードを使っては勉強にならないと思われるかもしれませんが、自力でゼロからコードを
書くというアプローチで見当違いの方向に進んでしまうと、時間ばかりかかって勉強の効率が
上がらないかもしれません。

なので、自分としては、まずウィザードベースで作ってみて、その後自力でコードを書く際に
もウィザードベースで作ったコードを参考にすることをお勧めします。

引用返信 編集キー/
■72188 / inTopicNo.4)  Re[2]: データグリッド内の更新
□投稿者/ ロギー (4回)-(2014/05/23(Fri) 13:40:07)
2014/05/23(Fri) 13:47:33 編集(投稿者)
2014/05/23(Fri) 13:44:22 編集(投稿者)


> System.Windows.Forms.DataGrid「データグリッド」と
> System.Windows.Forms.DataGridView「データグリッドビュー」は
> まったく別のコントロールですが、今回は、
> DataGridView に関してという認識でよろしいでしょうか。

失礼しました。
DataGridViewです。



> 『"Data Source=" & path & ";" & _』や
> 『"Data Source=path.mdb;" & _』など。
ミスです、修正致しました。


> たとえば、このような手順です。
> http://blog.livedoor.jp/akf0/archives/51536291.html
> 
> 上記は SQL Server が相手なので、SqlCommand や SqlDataAdapter が使われていますが、
> 今回は Access が相手なので、OleDbCommand や OleDbDataAdapter に置き換えれば OK です。

置き換えて書いてみましたところ、
データを更新するボタンを押したときに、

'データの更新
        result = adapter.Update(ds.Tables(0))  ここで


同時実行違反 : UpdateCommand によって、処理予定の 1 レコードのうち 0 件が処理されました。

というエラーが出ました。

フォームロード時にデータグリッドビューを表示し、
更新ボタンがあるという状態です。



前と同じ値であればUpdateできるが、異なる値だと出来ない
という状態です。

異なる値に変更したいのですが、
これはaccess側に原因があるのでしょうか。

同時実行違反のエラーの関連ページも見ましたが、
イメージが付かないです。



Imports System.Data.SqlClient
Imports System.Data.OleDb


Public Class Form1


    Private connection As OleDbCommand
    Private adapter As OleDbDataAdapter
    Private ds As DataSet


    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim OLEDBCon As OleDb.OleDbConnection = New OleDb.OleDbConnection
        Dim OLEDS As DataSet = New DataSet("TABLEDATA")



        connection = New OleDbCommand()


        'DBへの接続
        OLEDBCon.ConnectionString = _
          "Provider=Microsoft.Jet.OLEDB.4.0;" & _
          "Data Source=Sample.mdb;;" & _
          "Persist Security Info=False"


        'データの取得
        ds = New DataSet()


        Dim sql As String
        sql = "SELECT * FROM Test"


        adapter = New OleDbDataAdapter()
        adapter.SelectCommand = New OleDbCommand(sql, OLEDBCon)
        adapter.SelectCommand.CommandType = CommandType.Text
        adapter.Fill(ds)

        Me.DataGridView1.DataSource = ds.Tables(0)

        adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey

    End Sub



    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        '更新用SQLの取得
        Dim builder As OleDbCommandBuilder = New OleDbCommandBuilder(adapter)
        builder.GetUpdateCommand()
        Dim result As Integer


        'データの更新
        result = adapter.Update(ds.Tables(0))

    End Sub

End Class

引用返信 編集キー/
■72191 / inTopicNo.5)  Re[3]: データグリッド内の更新
□投稿者/ 魔界の仮面弁士 (21回)-(2014/05/23(Fri) 15:28:02)
2014/05/24(Sat) 15:49:08 編集(投稿者)

No72188 (ロギー さん) に返信
> "Data Source=Sample.mdb;;" & _
今度はセミコロンが 2つに?


> 同時実行違反 : UpdateCommand によって、処理予定の 1 レコードのうち 0 件が処理されました。

これは、更新 SQL はエラー無く実行されたものの、更新処理を実行してみても
『更新されたレコードが無い状態(0件)』であったことを意味します。
(ここでいう更新 SQL とは、adapter.UppdateComand に設定された UPDATE SQL のことです)


このメッセージが発生する要因は幾つかありますが、たとえば下記が挙げられます。

(可能性1)元テーブルに主キーが無いため、更新対象のレコードを特定できない。

(可能性2)更新前に、他ユーザーなどが同一レコードを既に更新していた。

(可能性3)列名などに、曖昧な型や予約語が含まれており、誤ったデータ比較が行われている。
----

特に可能性が高いのは 上記 3 ですね。過去に、以下のようなケースを経験しています。


(1)「No」列

ナンバーの意味で用いていたつもりが、FALSE の意味(Access の YES/NO リテラル)と
誤解されて処理されていました。列名を変更するか、SQL を修正して
「[No]」あるいは「`No`」と表記することで回避できます。


(2) 日付時刻型

日付型の項目があった場合、そこに時刻情報が含まれていた場合(0時0分0秒以外だった場合)に
正しく処理されないというものです。この場合は、Parameter のデータ型を
Date 型 から DateTime 型に修正することで回避できます。
http://dobon.net/vb/bbs/log3-42/25261.html



> 同時実行違反のエラーの関連ページも見ましたが、
> イメージが付かないです。

同時更新に関しては、2 種類のパターンがあります。早い者勝ちか、最後の更新を優先するかです。

 (A) 先に書いた方が優先される。後から更新することはできずエラーとして対処する。
 (B) 後に書いた方が優先される。先に更新した内容は失われる。

これらは、UpdateCommand の内容によって調整されます。イメージ的には

(A)なら「UPDATE 表 SET 列1=新しい列1値 WHERE 主キー列=元の主キー値 AND 列1=元の列1値」
(B)なら「UPDATE 表 SET 列1=新しい列1値 WHERE 主キー列=元の主キー値」

のような SQL を割り当てる感じです。

同時更新が発生すると、それぞれ
A なら『処理予定の 1 レコードのうち 0 件が処理される』のでエラーとなり、
B なら『処理予定の 1 レコードのうち 1 件が処理される』ので正常実行となります。

どちらが好ましいのかは、アプリケーションの案件次第です。


> Imports System.Data.SqlClient
> Imports System.Data.OleDb
今回は mdb が対象なので、System.Data.SqlClient 名前空間は不要かと。

> Dim OLEDS As DataSet = New DataSet("TABLEDATA")
この変数は不要では無いでしょうか。
宣言した後、そのあとどこにも使われていないようですし。
引用返信 編集キー/
■72199 / inTopicNo.6)  Re[3]: データグリッド内の更新
□投稿者/ WebSurfer (266回)-(2014/05/24(Sat) 12:09:36)
No72188 (ロギー さん) に返信

楽観的同時実行制御に引っかかる原因を探して解決しないことには先に進めないと思い
ますが、それを承知で一言・・・

CommandBuilder でクエリを自動生成させると、どうしても楽観的同時実行制御のための
UPDATE, DELETE クエリが生成されてしまいます。

詳しくは、以下のページの「更新および削除のオプティミスティック同時実行制御」の
セクションを見てください。

CommandBuilder でのコマンドの生成
http://msdn.microsoft.com/ja-jp/library/tf579hcz(v=vs.110).aspx


「楽観的同時実行制御」ではなくて「後勝ちルール」(魔界の仮面弁士さんのレスにあ
るパターン (B) )にしたい場合は、CommandBuilder は使わないで、自力でコードを書
いて OleDbDataAdapter の UpdateCommand, DeleteComannd, InsertCommand を設定せ
ざるを得ません。

それは初心者には結構難しいと思いますので、くどいようですが、先のレスに書いたよう
に Visual Studio のデータソース構成ウィザード等を使って作るアプローチをお勧めし
ます。

「楽観的同時実行制御」にするか「後勝ちルール」にするかはウィザード実行中に選択で
きます。

さらに、フィールド名に予約語を使っているような場合でも問題がないようなコードを
自動生成してくれるなどのメリットも多いです。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -