none
UpdateCommandを追加する方法? RRS feed

  • 質問

  • UpdateCommandを追加する方法がわからず困っています。

    [T_サブ]と [T_商品]の2つのテーブルを結合してデータグリッドに表示する所まではできています。
    このとき,「数量」フィールドの値を変更してbtnUpdateボタンをクリックしたとき,「金額」フィールドに再計算した結果を表示しようとして,下のようにUpdateCommandを追加してみましたが,
       オブジェクト参照がオブジェクト インスタンスに設定されていません。
    というエラーになるのですが,これへの対処の方法を教えていただけないでしょうか。
    --------------------------------------------------------------------------------
    //データアクセス用のコンポーネント
    private OleDbConnection ocnSample = new OleDbConnection();
    private DataSet dsSub = new DataSet();
    private DataTable dtSub = new DataTable();
    private OleDbDataAdapter odaSub = new OleDbDataAdapter();

    private void Form1_Load(object sender, EventArgs e)
    {
        //DB接続
        ocnSample.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=D:\\ADO_DB\\Sample.mdb";
        //DataAdapterの作成
        odaSub =new OleDbDataAdapter
            ("SELECT [T_サブ].注文NO, [T_サブ].商品番号, [T_商品].商品名, [T_商品].単価, [T_サブ].数量, "+
             "[T_商品].単価 * [T_サブ].数量 AS 金額 "+
             "FROM ([T_サブ] INNER JOIN [T_商品] ON [T_サブ].商品番号 = [T_商品].商品番号) "+
             "ORDER BY [T_サブ].注文NO",ocnSample);
        //(Error)オブジェクト参照がオブジェクト インスタンスに設定されていません。
        odaSub.UpdateCommand.CommandText ="UPDATE [T_サブ] SET 注文NO = ?, 商品番号 = ?, 数量 = ? " +
                               "WHERE (注文NO = ?) AND (商品番号 = ?) AND (数量 = ?)";
    }

    private void btnLoad_Click(object sender, EventArgs e)
    {
        dsSub.Clear();
        odaSub.Fill(dtSub);
        dataGridView1.DataSource = dtSub;
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        int iRows = odaSub.Update(dtSub);
        dsSub.Clear();
        odaSub.Fill(dtSub);
        MessageBox.Show("Update " + iRows.ToString());
    }

    2006年8月6日 5:23

回答

  • odaSub.Fill(dtSub); しているので、これだけでdataGridView1の再表示は自動的にされると思うんですが、dtSubがクリアされていないので、ひょっとして金額が更新された新しいレコードがdataGridView1の最後の方に追加されてたりしないのかなぁ?と思った次第です。でもこれだとさすがに気付きそうなので、私も半信半疑なのです。

    それから話は変わってパラメータの指定ですが、
    UpCommand.Parameters.Add("old注文NO", OleDbType.Integer, 5, "注文NO").SourceVersion = DataRowVersion.Original;
    みたいな感じで一行ずつ指定していかないと、まずい気がします。

    2006年8月7日 4:38
    モデレータ

すべての返信

  • んと、OleDbCommandのインスタンスを生成してからそれをodaSub.UpdateCommandに代入する必要があるかな?

     

    2006年8月6日 6:26
  • どっとねっとふぁんさんありがとうございます。

     どっとねっとふぁん さんからの引用
    OleDbCommandのインスタンスを生成してからそれをodaSub.UpdateCommandに代入する必要があるかな?

    OleDbCommand UpCommand  
           =new OleDbCommand ("UPDATE [T_サブ] SET 注文NO = ?, 商品番号 = ?, 数量 = ? " +
              "WHERE (注文NO = ?) AND (商品番号 = ?) AND (数量 = ?)",ocnSample );
    odaSub.UpdateCommand = UpCommand;

    としてみたところ,Updateの実行時に下のようなエラーが出てしまいました。

    private void btnUpdate_Click(object sender, EventArgs e)
    {
          int iRows = odaSub.Update(dtSub); //(Error)1 つ以上の必要なパラメータの値が設定されていません。
          dsSub.Clear();
          odaSub.Fill(dtSub);
          MessageBox.Show("Update " + iRows.ToString());
    }

    2006年8月6日 7:36
  •  zen73 さんからの引用
    (Error)1 つ以上の必要なパラメータの値が設定されていません。

    以下のようにパラメーターを設定してみました。


    UpCommand.Parameters.Add("注文NO", OleDbType.Integer, 5, "注文NO");
    UpCommand.Parameters.Add("商品番号", OleDbType.VarWChar, 10, "商品番号");
    UpCommand.Parameters.Add("数量", OleDbType.Integer, 5, "数量");
    OleDbParameter parameter;
    parameter = UpCommand.Parameters.Add("old注文NO", OleDbType.Integer, 5, "注文NO");
    parameter = UpCommand.Parameters.Add("old商品番号", OleDbType.VarWChar, 10, "商品番号");
    parameter = UpCommand.Parameters.Add("old数量", OleDbType.Integer, 5, "数量");
    parameter.SourceVersion = DataRowVersion.Original;

    odaSub.UpdateCommand = UpCommand;



    [数量]を更新することはできましたが,再計算はできていません。
    1度終了してから再実行すると,金額がきちんと計算されて表示されます。
    このこと「再計算」を,btnUpdateでするにはどうしたらいいのでしょうか。

    《追記》勉強のために3種類のコードを書いています。
        a データ接続にウィザードを使用し,プロパティも画面上で設定する
        b データ接続のみにウィザードを使用する
        c データ接続,プロパティ設定の両方をコードに書く
    お聞きしているのは<c>ですが,a,bともに再計算は思い通りに動いていますので,やはりUpdateコマンドの追加の仕方に問題があるように感じているのですが・・・・・。

    2006年8月6日 8:48
  • 画面上の表示が最新のものに切り替わらない、ということですよね?
    再表示すればデータは計算されているということであれば、Updateコマンドに問題があるのではなく、画面表示の更新が行われていないのだと思います。
    btnUpdateのクリック時にデータテーブルの更新は行っているようですから、最後にデータグリッドのDataBindメソッドを実行してあげればいいと思います。

    要するに、内部のデータは置き換わっているけどデータグリッドのほうはデータが置き換わったことを知らない、という状態なのでプログラムのほうから表示しなおすように言ってあげないといけない、と。

    2006年8月7日 2:00
  • dsSubにdtSubを追加しているコードが無いのが気になります。もし追加していないのでしたら、dsSubが全く使われておらず、dsSub.Clear()を実行しても、何もしないのと同じことになってしまっています。
    従って、ふたたびFillすれば、主キーがダブらなければ単純にdtSubに追加されてしまいますが、そのような現象は起きていないのでしょうか?

    2006年8月7日 2:29
    モデレータ
  • あ、確かに気になったとこだけど、書いてないとこで何かやってるかな、と思ってました。
    再表示がうまくいってはじめて気づく問題点かも(w

    2006年8月7日 2:50
  • odaSub.Fill(dtSub); しているので、これだけでdataGridView1の再表示は自動的にされると思うんですが、dtSubがクリアされていないので、ひょっとして金額が更新された新しいレコードがdataGridView1の最後の方に追加されてたりしないのかなぁ?と思った次第です。でもこれだとさすがに気付きそうなので、私も半信半疑なのです。

    それから話は変わってパラメータの指定ですが、
    UpCommand.Parameters.Add("old注文NO", OleDbType.Integer, 5, "注文NO").SourceVersion = DataRowVersion.Original;
    みたいな感じで一行ずつ指定していかないと、まずい気がします。

    2006年8月7日 4:38
    モデレータ
  • 感激!!。お陰様ですべてがうまくいきました。trapemiyaさん,どっとねっとふぁんさん,ありがとうございました。

     trapemiya さんからの引用
    UpCommand.Parameters.Add("old注文NO", OleDbType.Integer, 5, "注文NO").SourceVersion = DataRowVersion.Original;
    みたいな感じで一行ずつ指定していかないと、まずい気がします。


    UpCommand.Parameters.Add("old注文NO", OleDbType.Integer, 0, "注文NO").SourceVersion = DataRowVersion.Original;
    UpCommand.Parameters.Add("old商品番号", OleDbType.WChar, 10, "商品番号").SourceVersion = DataRowVersion.Original;
    UpCommand.Parameters.Add("old数量", OleDbType.Integer, 0, "数量").SourceVersion = DataRowVersion.Original;

     

    と書き直しました。(実はこの部分が気になっていたのです)
     trapemiya さんからの引用
    dtSubがクリアされていないので、ひょっとして金額が更新された新しいレコードがdataGridView1の最後の方に追加されてたりしないのかなぁ?

    btnUpdateを押したとき,縦スクロールバーがすぅーっと動くのが見えて納得。みごとなご推察,さすがです。

           
    private void btnUpdate_Click(object sender, EventArgs e)
    {
           int iRows = odaSub.Update(dtSub);
           dtSub.Clear();
           odaSub.Fill(dtSub);
           MessageBox.Show("Update " + iRows.ToString()); 
           dataGridView1.DataSource = dtSub; 
    }

     

    皆さんのご助言に感謝します。

    *このあと列の追加や削除などを考えていたのですが,しんどくなってしまいました。
     プロの皆さんはデータ接続からコードを書き始めるのが必要な場合があるのでしょうか。

    2006年8月7日 6:21
  •  zen73 さんからの引用

    プロの皆さんはデータ接続からコードを書き始めるのが必要な場合があるのでしょうか。

    プロかどうかは別として・・・(^^;

    例えば、Visual StudioというIDEを使わずに、エディタでC#のコードをごりごりと書く場合には、否が応でも全て自分でコードを書かなければなりません。これでは開発効率が悪いため、Visual Studioを使い、Visual Studioに裏でコードを自動生成させていたりするわけです。
    プロパティの設定を例にあげます。全てコードでプロパティを設定する方法もありますし、Visual Studioに用意されたプロパティウインドウで全て設定する方法もあります。コードで設定するよりもプロパティウインドウで見た方が一覧性も良いですし、設定しやすいと思います。特にフォントや色なんかを設定する場合は便利です。

    つまり、Visual StudioなどのIDEはこういう便利さを提供しているものだと考えれば、答えが見つかるのかもしれません。Visual Studioが用意している便利な機能はできるだけ利用し、それでは実現できないようなケースの場合に、自分でコードを書くことになるのが基本だと思います。もちろん、組織で開発する場合などの保守性やコーディング規則などによって一概には言えないと思います。

    さて、ようやく質問に対する本題なのですが(^^; 基本的な考え方は上で述べた通りです。で、具体的にデータ接続から書き始める場合ですが、Zen73さんのように自分で理解を深める時や、いろいろなテストをする場合などを除いて、私の場合はほとんどありません。しいて言えば、複数のDataReaderを開く時に、動的かつ一時的に接続を作成する場合などでしょうか? しかし、これもMARSの登場によって必須ではなくなりました。

    また、お聞きになったことがあると思いますが、従来から3階層アプリという考え方があって、データアクセス層とプレゼンテーション層を分けようという考え方があります。これと今回の場合はちょっと違うのですが、基本的な考え方は同じで、できるだけプレゼンテーションなどのロジック部分と、お決まりのデータアクセス部分を分けておくと、保守が簡単で、かつ、他のデータベースへの移行なども楽になるというメリットがあります。

    だらだらと書いてしまいましたが、ユーザーから見るとまったく同じに見えるアプリケーションでも、内部の作りはさまざまになるわけで、この違いが、保守性やら拡張性やらの違いにつながってきます。つまり、ユーザーから、この部分をこう直してと言われた場合、非常に工数がかかるシステムとそうでもないシステムに分かれるわけです。 この辺りは、どういうふうにコードをかけばアプリケーションが思うように動くかというレベルから一歩進んで、どうやれば柔軟性にとんだアプリケーションを作れるかというところの話になってきます。
    こういう一歩先を見て、柔軟性にとんだアプリケーションを作れるかどうかというのが、本当の実力の差なんだと思います。

    なんだか取りとめも無い文章になっちゃいましたね。(^^;

    2006年8月8日 4:15
    モデレータ
  • 丁寧に答えてくださり,ありがとうございました。
    2006年8月8日 10:10
  • 一つ書き忘れてました。以下のことについて既にされているのなら、ごめんなさい。

    OleDbConnectionやOleDbDataAdapterなどはデフォルトでツールボックスに表示されなくなりましたが、ツールボックスで右クリックして「アイテムの選択・・・」を開き、それらにチェックしてあげれば、ツールボックスに表示されるようになります。

    DataAdapterやSqlCommandたちは代打の切り札??
    http://blogs.wankuma.com/trapemiya/archive/2006/04/17/22530.aspx

    で、ちらっと書いてますが、特にSqlConnectionやSqlCommandは今後も使う機会が多いと思います。
    で、これらはツールボックスからフォームへドラッグアンドドラッグしてきますが、プロパティウインドウで設定できるものは設定してしまっています。
    SqlConnectionのConnectionStringをコードから変えれば、簡単にテスト系で動かすことも可能です。

    #TableAdapterの内部で使っているDataAdapterがprivateなところとか(FillはVirtualなのに・・・)、CommandCollectionがpublicでないところなど謎が多いですが)、これらについてはまたブログで書きたいと思ってます。

    2006年8月9日 10:47
    モデレータ