none
FindBy... RRS feed

  • 質問

  • Visual Basic 2005 Express Edition & SQL Server 2005 Express Editionを利用してます。

     

    データテーブルには自動生成されたメソッドでFindBy...って感じのプライマリーキーをキーとしてRow構造体で返してくれるのがありますが、テーブルアダプタには自動生成はされないですよね? InsertやUpdate、Fill&Get等は自動生成されてますが、一般的にはテーブルアダプタ使ってこんな事(プライマリーキーをキーとしてレコードを呼び出す)はしないんですか?

     

    実は最初プログラムを書き始めた際にはFillにてデータテーブルに全て取得し、そのデータテーブルのFindBy...メソッド使ってRow構造体を取得。更新データをRow構造体に反映した後、テーブルアダプタのUpdateメソッドにRow構造体渡して更新処理しようとしてました。しかし、この方法だと更新するレコードを含むテーブル自体が数万件とかの大きいものではFillだけでも相当な時間を要しますよね?そこでデータテーブルには取り込まずにテーブルアダプタとしてFindBy...メソッド的にRow構造体を返してくれるものがあれば、単一レコードの更新ではスムーズに行えるんじゃないかと思う訳です。でも、そのFindBy...メソッドが自動生成されないのであれば、一般的には違う方法なのかな~と疑問に思ってしまいました。

     

    テーブルアダプタを使うアクセス方法にVisual Basic 2005からはなったと手持ちの参考書やオンラインなんかのもので読んで自分なりに奮闘してますが、この極一般的にありえる更新処理で悩んでます。ご助言頂ければ幸いですm(__)m

    2007年9月3日 1:39

回答

  •  サメの餌 さんからの引用

     本来同じテーブルへの挿入なら1レコード毎にconnectなんて無駄な事をせずに同一テーブルへの挿入が繰り返される間1回のconnectにするべきなんですよね^^;

    この辺りの動作は、何とかDataSet.Designer.cs(C#の場合)に書かれているのですが、コマンド実行前の接続状態を保持しておき、コマンド実行後にコマンド実行前の接続状態に戻すようになっています。つまり、コマンド実行前にclose状態であれば、コマンド実行後にcloseに戻されます。以上より、場合によっては1レコード毎にデータベースへ接続、切断を繰り返すことになりそうです。

     

     サメの餌 さんからの引用

     この辺りがtrapemiyaさんがご指摘の単に1レコード挿入するだけならテーブルアダプタ使うもの良いけど、そうでないならやはりストアドプロシージャとかでの実現を考慮すべきって事なんですよね?

    というより、テーブルアダプタはDataAdapter、DataSet、DataTableなどをあまり意識せずにデータを扱えるようにするものだと思いますので、データベースのレコードを1件更新するような場合は、オーバースペックじゃないかと思うのです。

     

     サメの餌 さんからの引用

    スレッド的にはちょっと中途半端な感じですが、今回の質問のFillBy...メソッドをテーブルアダプタにって話は、はやり現実的ではないって事で締めちゃってもよろしいですかね?

    私が判断することではありませんが、今回のケースではFillBy...メソッドを使うことは方向性が違うように思います。

    2007年9月25日 6:30

すべての返信

  • TableAdapterでも内部に型付けされたDataTableを持っていますので、そのメソッドとしてFindBy系メソッドは自動生成されています。

    またFindBy系メソッドはあくまでDataTableのRowsコレクションに対して実行されるものですから、いくらFindBy系メソッドを使おうと、FillでDataTableへデータを一旦取り込まなければなりません。言われているように単一のレコードを更新されたいのであれば、DetaTableは使わず、SQL文を直接データベースのテーブルに対して投げるべきでしょう。

     

    #追記。もちろん、ストアドプロシージャで行う方が良い。

    2007年9月3日 2:47
  • trapemiyaさん、ありがとうございます。

     

    確かにSQL文を直接投げるのは最終手段だとは思ってます。折角の新機能なのでちょっと手探り状態ではありパフォーマンスに非常に疑問は残ってるんですが、昨晩試しにテーブルアダプタにFindBy...を手動で追加してみました。ちょっとテーブルとか多くてこの修正作業がしばらく掛かりますので結果報告を含めてしばらく掛かる事をご容赦下さいm(__)m

     

    それと、追記についてなんですが、なにぶんプログラミング経験だけはやたらと長いんですが、第一線から離れて10年以上経ち、最新技術(って程の事でもないんですが)になかなか追いつけなくて(;一_一) データベース自体ある程度知識があったりするのですが、SQL系なんかは今回初めて(今まではdBaseからAccessへという感じのアプリより、プログラミングではB-trieveとかのみだったり^^;)なので、ストアドプロシージャが良いとかって事をあちこちの参考資料やサイトで目にするものの、未だ手をつけてません。ですので、テーブルアダプタに追加しているFindBy...があまりにパフォーマンスが悪かったら、次の段階としてストアドに足を踏み入れてみようかと思います。

     

    #テーブルアダプタにしがみつくより即座にストアドに移行した方が無駄が少ないですかね?^^;

    2007年9月4日 0:56
  • 以下、TableAdapterに関する私の個人的感想です。TableAdapterはDataSet、DataTable、DataAdapterをラップしたものです。TableAdapterが無い頃は、これらDataSet、DataTable、DataAdapterを理解し、それ相応のコードを記述しなければなりませんでした。これはとても簡単と言えるものではありませんでした。そこで、これらをラップして簡単に扱えるようにしたものがTableAdapterというわけです。そういう意味では新しい技術というわけではありません。

    以上のことからわかるように単一のレコードを更新するだけのためなら、TableAdapterを使うことはあまり適していないことがわかると思います。もっとも、TableAdapterにDataTableを作成せずにクエリだけを追加して、それを利用してレコードの更新を行うこともできます。プログラムのいろいろな箇所で同じクエリを何度も発行するのであれば、これも有効な手段になり得るでしょう。

     

    もし、更新するためだけのためにDataTableへレコードを抽出し、そこからFindBy系メソッドで特定のレコードを探し出し、それを更新し、そこからUpdateでデータベースへ更新処理を行うのであれば、パフォーマンス以前に考え方としては誤った方向です。単一のレコードを更新するためだけのために、DataTableを使う必要は全くないからです。

     

    また既に気づかれていらっしゃいますが、TableAdapterにしがみつく必要は全くありません。必要だと思うときに使えばいいだけです。カメラで言えばTableAdapterはAuto撮影モードみたいなものでしょう。早い動きを止めたければシャッタースピード優先モードに切り替えなければなりません。これと同じようにあらゆる場面でTableAdapterは万能ではありません。

    2007年9月4日 1:39
  • 何とか、少しでもヒントになればと思い、浅はかな知恵と経験からですが、書かせていただきます。

    Trapemiya様も

    もっとも、TableAdapterにDataTableを作成せずにクエリだけを追加して、それを利用してレコードの更新を行うこともできます。プログラムのいろいろな箇所で同じクエリを何度も発行するのであれば、これも有効な手段になり得るでしょう。」

    と書いておられるように、TableAdapterは、さまざまなクエリを格納できます。

    TableAdapter右クリックのクエリの追加で、クエリを

    Select * from テーブル where 列=@値 など (必要ならば、where句にパラメータを増やします)

    のように、指定すると、FillByメソッド、GetDataByメソッドが追加されます。Fillのときよりも、引数がパラメータの数だけ増えています。

    今回、サメの餌様の案件で、更新処理以外にそれにまつわるものがどのようなものがあるのかわかりませんが、私の場合は、Controlとのデータバインドを行い、何十行かを読み込むことが多いので、先ほどのwhereには範囲などを指定します。

    例:  where 列 between @A and @B など。

     

    そして、FillByによって、DataTableにデータを読み込む方法を使っています。そのDataTableにBindingSourceを介して、DataGridViewなどのコントロールとデータバインドさせます。そして、更新は、TableAdapterのプロパティを見ると、UpdateCommandとあるので、最適なコマンドを入れてやります。私の場合は、ここはいつも、CommandTypeをStoredProcedureにして、更新用ストアドプロシージャを指定しています。そのあと、Parametersのコレクションエディタで、

    パラメータのSourceColumnに対応列を指定します。そうすることで、DataTableの列の値が、Updateメソッド実行時に、自動的にパラメータに渡されます。

     

    ちなみに、DataRow(DataSet自体も)は構造体ではなくクラスなので、すべてヒープに格納されます。

    2007年9月7日 16:56
  • ちょっと間があいてしまいましたm(__)m Ogachaさんもコメントありがとうございます。

     

    途中経過ですが...

     

    テーブルアダプタにOgachaさんも書いている感じで「クエリの追加...」にて新たなFillByとGetDataByのセットを全てのテーブルに対して追加作業を行いました。40個程度あり、毎晩娘を風呂に入れた後に寝るまでに2時間程度を使って1日3個ずつ程度しか進めなくて...実は仮想マシン上にテスト環境を含めた開発環境を構築してまして、VB2005 Express Editionは最低256MB、推薦512MBって事でぎりぎりの512MBメモリでの仮想マシンを構築している為、クエリの追加作業が非常にレスポンスが悪いんです。メモリやリソースを多大に消費してるらしく、激しくスワップが発生している感じ(>_<) そんな言い訳でこの程度の作業だけで2週間近くを費やしました。

     

    今後、この追加したクエリを利用して該当するレコードのみをデータテーブルに取り込んでの更新処理でのテストを行い、余分なデバックとデータベース構築のパフォーマンスを確認した後に、多分ストアドプロシージャの追加を行い再度作り直しをする予定です。なぜこの様なちょっと無駄の多い作業をしているかと申しますと、既に更新データの反映処理部分のコーディングがDataRowクラスに対して書かれているので、取敢えずその部分を有効活用して作業を減らしたつもりです^^;

     

    実は、ストアドプロシージャもちょっとだけ試したというか調べたりしたんですが...テーブルアダプタを右クリックから「クエリの追加...」を選択するとストアドプロシージャの追加も選択出来ますよね?で、あれで更新用に追加してみると、普通にプライマリキーを指定し、更新データとして各項目データをパラメータとして渡す感じのメソッドがテーブルアダプタに追加になりますよね?これがストアドプロシージャ?っと疑問に思いながら、自分のイメージとして、これだと、データの追加更新処理として、TableAdapter.Insert()メソッドでまず実行し、エラーになったらTableAdapter.UpdateBy()メソッドで更新処理を試みる的な方法では、100を超える項目があるテーブルでは2度も引数渡しが必要になるのが気になったりしてます。理想としてはストアドプロシージャに全ての項目を引数として渡して、ストアドプロシージャの中で挿入試して重複エラーになったら更新って感じのものを各テーブルに対して作りたいなと考えてます。この実現方法をどうすれば良いのかが理解出来ていませんので、まずはその糸口探しもしなければと思ってます^^; というのも、テーブルアダプタで追加するストアドプロシージャはユーザーが処理を書くものではないですよね?サーバエクスプローラ側の該当データベースからのストアドプロシージャ追加だと殆ど全てをユーザーが一から書く感じがしました。しかし、いや、最近の環境ではそのストアドプシージャがVBなんかも使えるという事も読みましたが、T-SQL(?)で記述するのが正解? ちょっと直ぐに手を付けられるものではない感じがしましたので、ちょっと遠回りになるかもなんですがまずはテーブルアダプタのクエリの追加でちょっとテストを進めます。

     

    またしばらく間があくかと思いますが、ご了承下さい。結果報告します。で、次のステップはまた質問するかもですが、その際にはまたアドバイス等頂ければ幸いです。

    2007年9月14日 0:56
  •  サメの餌 さんからの引用

    毎晩娘を風呂に入れた後に寝るまでに2時間程度を使って1日3個ずつ程度しか進めなくて...

     

    わかります、わかります。なので、時間があいても全然OKですよ。

     

     サメの餌 さんからの引用

    実は、ストアドプロシージャもちょっとだけ試したというか調べたりしたんですが...テーブルアダプタを右クリックから「クエリの追加...」を選択するとストアドプロシージャの追加も選択出来ますよね?で、あれで更新用に追加してみると、普通にプライマリキーを指定し、更新データとして各項目データをパラメータとして渡す感じのメソッドがテーブルアダプタに追加になりますよね?

     

    その通りです。ストアドプロシージャがデータベースに作成されています。こうやって作成されたストアドプロシージャを雛形にしてストアドプロシージャを開発していくと楽な場合があります。

     

     サメの餌 さんからの引用

    理想としてはストアドプロシージャに全ての項目を引数として渡して、ストアドプロシージャの中で挿入試して重複エラーになったら更新って感じのものを各テーブルに対して作りたいなと考えてます。この実現方法をどうすれば良いのかが理解出来ていませんので、まずはその糸口探しもしなければと思ってます^^;

     

    ストアドプロシージャ内でレコードの存在チェックをして、あれば更新、なければ追加をしても良いのですが、ほとんど追加になるという場合は、以下のようにもできます。

     

    ストアドプロシージャでレコードの存在チェックをせずに追加・更新する。
    http://blogs.wankuma.com/trapemiya/archive/2006/02/23/21482.aspx

     

     サメの餌 さんからの引用

     というのも、テーブルアダプタで追加するストアドプロシージャはユーザーが処理を書くものではないですよね?サーバエクスプローラ側の該当データベースからのストアドプロシージャ追加だと殆ど全てをユーザーが一から書く感じがしました。

     

    上でも述べましたが、テーブルアダプタによって作成されるストアドプロシージャは雛形と考え、それを元にストアドプロシージャを開発して、完成したストアドプロシージャをテーブルアダプタで利用するという流れが楽かもしれません。

    参考までに、私は一からストアドプロシージャを作成し、それを直接プログラムからキックすることがほとんどです。

     

     サメの餌 さんからの引用

    しかし、いや、最近の環境ではそのストアドプシージャがVBなんかも使えるという事も読みましたが、T-SQL(?)で記述するのが正解? ちょっと直ぐに手を付けられるものではない感じがしましたので、ちょっと遠回りになるかもなんですがまずはテーブルアダプタのクエリの追加でちょっとテストを進めます。

     

    SQL CLRのことだと思いますが、T-SQLと比較して一長一短あります。いずれにしても、まずはT-SQLを経験された方が良いと思います。

    2007年9月14日 2:40
  • ご無沙汰しております。

     

    あの後、少しテストしてましたが、色々他の問題に直面し、ちょっと泥沼に嵌り込んじゃった感じでした。普通にテーブルアダプタのInsertメソッド使ってレコードの追加を何度も繰り返す部分があったりするのですが、そこでエラーになって、まあ、処理の流れから今回の質問FillByメソッドに飛ぶ様な流れ(挿入でエラーなら更新ってパターンです)だったのですが、そのFillBy後の更新でもエラーとなるのでトレースで調べていた所、そもそも挿入の繰り返しをテーブルアダプタで行う場合、同じテーブル違うテーブル特に意識せずに挿入時に内部的にconnectしてるんですよね? 本来同じテーブルへの挿入なら1レコード毎にconnectなんて無駄な事をせずに同一テーブルへの挿入が繰り返される間1回のconnectにするべきなんですよね^^; この辺りがtrapemiyaさんがご指摘の単に1レコード挿入するだけならテーブルアダプタ使うもの良いけど、そうでないならやはりストアドプロシージャとかでの実現を考慮すべきって事なんですよね?

     

    ちょっと遠回りになりましたが、そんな経験しながら、実はデータテーブルファイル(あっ、データセットファイルだったかちょっと記憶が曖昧ですが、テーブルとかを並べて表示して関連付けとか出来るファイルの事です)がVB2005 Express Editionで開けない状態になり、そのプロジェクトフォルダ丸ごと捨てる決心をしました。実はバックアップがちょうど今回の作業(テーブルアダプタへFillByメソッドの追加する作業)前の状態のみでしたので、これを期にストアドプロシージャでの実装を試みようかと思います。 やってたのは試しにテーブルアダプタで「クエリの追加...」からのストアドプロシージャの追加をしたり、出来たものを削除したりしていた所、沢山のエラーメッセージが出たりしたので一旦統合環境を終了させ、その際にセーブするか確認されたので、今回のはセーブしない方が良いかな~っと思いセーブせずに終了して、再度起動してプロジェクト開いたら、何とかdesigneファイルが見つかりませんとかになりそのプロジェクトは使えない状態と判断しました^^;

     

    スレッド的にはちょっと中途半端な感じですが、今回の質問のFillBy...メソッドをテーブルアダプタにって話は、はやり現実的ではないって事で締めちゃってもよろしいですかね? 一応数日間は様子見た後に解決済みにさせて頂きますね。 今後はストアドプロシージャでの実装を試みた時にまた分からない事がありましたら助言して頂ければ幸いです。ありがとうございました。

    2007年9月25日 4:43
  •  サメの餌 さんからの引用

     本来同じテーブルへの挿入なら1レコード毎にconnectなんて無駄な事をせずに同一テーブルへの挿入が繰り返される間1回のconnectにするべきなんですよね^^;

    この辺りの動作は、何とかDataSet.Designer.cs(C#の場合)に書かれているのですが、コマンド実行前の接続状態を保持しておき、コマンド実行後にコマンド実行前の接続状態に戻すようになっています。つまり、コマンド実行前にclose状態であれば、コマンド実行後にcloseに戻されます。以上より、場合によっては1レコード毎にデータベースへ接続、切断を繰り返すことになりそうです。

     

     サメの餌 さんからの引用

     この辺りがtrapemiyaさんがご指摘の単に1レコード挿入するだけならテーブルアダプタ使うもの良いけど、そうでないならやはりストアドプロシージャとかでの実現を考慮すべきって事なんですよね?

    というより、テーブルアダプタはDataAdapter、DataSet、DataTableなどをあまり意識せずにデータを扱えるようにするものだと思いますので、データベースのレコードを1件更新するような場合は、オーバースペックじゃないかと思うのです。

     

     サメの餌 さんからの引用

    スレッド的にはちょっと中途半端な感じですが、今回の質問のFillBy...メソッドをテーブルアダプタにって話は、はやり現実的ではないって事で締めちゃってもよろしいですかね?

    私が判断することではありませんが、今回のケースではFillBy...メソッドを使うことは方向性が違うように思います。

    2007年9月25日 6:30