データベース データアダプタ データアダプタの概要 データアダプタは ADO.NET マネージプロバイダの重要な部分で有り データソースとデータセットの間の通信に使用されるオブジェクトのセットで有る マネージプロバイダには アダプタの他に接続オブジェクト データリーダーオブジェクト 及び コマンドオブジェクトが含まれる アダプタは データソースとデータセットの間でデータを交換する為に使用される 多くのアプリケーションでは 此れはデータベースからデータセットにデータを読み取って 変更されたデータをデータセットからデータベースに書き込む事を意味する 併し データアダプタは任意のソースとデータセットの間でデータを移動出来る 例えば Microsoft Exchange サーバーとデータセットの間でデータを移動するアダプタも考えられる 以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在も.NET Framework データプロバイダの主要なコンポーネントだが TableAdapter はデザイナで生成されるコンポーネントで アプリケーションとデータベースの間でデータを移動する処理を簡略化する TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い 一般に アダプタはデータセットとの間で何の様なデータを交換するかを指定出来る様に構成出来る 此れは多くの場合 データベースの読み取りや書き込みする時に呼び出される SQL ステートメントやストアドプロシージャへの参照と謂う形を取る Visual Studio に依って 此等のデータアダプタがデータベースで使用出来る様に成る OleDbDataAdapter オブジェクトは OLE DB プロバイダに依って公開される任意のデータソースと共に使用するのに適して居る SqlDataAdapter オブジェクトは SQL Server に固有のオブジェクトで有る 此のオブジェクトは OLE DB 層を経由する必要が無い為 OleDbDataAdapter クラスよりも高速で有る 但し SQL Server 7.0 以降丈で使用出来る OdbcDataAdapter オブジェクトは ODBC データソースへのアクセス向けに最適化されて居る OracleDataAdapter オブジェクトは Oracle データベースへのアクセス向けに最適化されて居る データアダプタ データ接続 データコマンド データリーダーは.NET Framework データプロバイダを構成するコンポーネントで有る Microsoft やサードパーティプロバイダには Visual Studio に統合出来る其の他の.NET Framework データプロバイダが用意されて居る 他の.NET Framework データプロバイダの詳細に付いては.NET Framework データプロバイダ を参照され度い アダプタの作成や操作には.NET Framework マネージプロバイダの名前空間の一部で有る以下の名前空間を使用出来る -1-
SqlClient マネージプロバイダ名前空間 OleDb マネージプロバイダ名前空間 一般に 各データアダプタは 1 つのデータソーステーブルとデータセット内の 1 つの DataTable オブジェクトとの間でデータを交換する データセットに複数のデータテーブルが含まれる場合 通常の方法と仕ては 複数のデータアダプタからデータセットにデータを供給し 其のデータを夫々れのデータソーステーブルに書き戻す データセットにテーブルを作成する場合は アダプタのメソッドを呼び出して SQL ステートメントやストアドプロシージャを実行する アダプタに依ってデータリーダーオブジェクト (SqlDataReader OleDbDataReader OdbcDataReader 又は OracleDataReader) が作成され データがデータセットに読み取られる データベースからデータを読み取る時にデータをデータセットに格納する必要が無い為 読み取り専用データを扱う時に使用すると効率的で有る 詳細に付いては 後の 読み取り専用データ を参照され度い 亦 SQL ステートメントを使用してデータセットを作成しなくても 直接 SQL ステートメントを実行出来る 詳細に付いては コマンドの使用 を参照され度い 同様に データベースを更新する場合は 適切な SQL ステートメントやストアドプロシージャを呼び出すアダプタのメソッドを呼び出して データベースに実際の更新を行う データアダプタ 及び 関連するテーブル データセット内に個別のテーブルを持つと謂う事は データアダプタが一般に テーブルを結合する SQL コマンドやストアドプロシージャを参照しない事を意味する 其の代わりに 関連する各テーブルからの情報は異なるアダプタに依って個別にデータセットに読み込まれる 此の時 DataRelation オブジェクトは データセットテーブル間の制約 ( 例えば 連鎖更新等 ) を管理し 関連するマスターレコードと子レコードの間で移動出来る様にする為に使用される 例えば Northwind と謂うデータベース内で 2 つの関連するテーブル Customers と Orders を使用するとする 結合を指定して 2 つのテーブルを 1 つの結果セットに纏める代わりに 通常は 2 つのアダプ -2-
タを定義する 1 つはデータセット内に Customers テーブルを作成し 今 1 つは Order レコードを別のデータセットテーブルに読み込む 多くの場合 此等の各アダプタには データテーブル内のレコード数を制限する為の選択基準が含まれる 亦 Order レコードが CustomerID フィールドに基づいて Customer レコードに関連付けられる事を指定する様に データセット内で DataRelation オブジェクトを定義する テーブルを引き続き個別に管理出来るが データソースからレコードをフェッチする前にテーブルを結合した場合は テーブルを個別に管理出来ない 関連するレコードを使用する場合は DataRelation オブジェクトのプロパティやメソッドを呼び出す事が出来る データリレーションシップの詳細に付いては データセットのリレーションシップ を参照され度い 接続オブジェクト データアダプタでデータを読み書きするには データソースへの接続が確立されて居る必要が有る 其の為 アダプタは 接続オブジェクト (SqlConnection OleDbConnection OdbcConnection OracleConnection) を使用してデータソースに接続する アダプタには 最大 4 つ迄の接続参照を含める事が出来る 此れは アダプタが実行する 4 種類のアクション ( 選択 更新 挿入 削除 ) に対応する ツールボックスの [ データ ] タブに有る接続オブジェクトの一覧を次の表に示す 接続オブジェクト SqlConnection OleDbConnection OdbcConnection OracleConnection 説明 SQL Server 7.0 以降のデータベースへの接続 OLE DB データソースへの接続 ODBC データソースへの接続 Oracle データベースへの接続 孰れの場合も 接続オブジェクトは データソース内の固有のセッションを表す 総ての接続オブジェクトには 接続の詳細 ( ユーザー ID パスワード 接続タイムアウト設定等 ) を設定 変更する為のプロパティが用意されて居る 亦 データベーストランザクションを開始 コミット ロールバックする為のメソッドも有る 接続オブジェクトの詳細に付いては データソースへの接続 を参照され度い セキュリティに関するメモ : 機密情報 ( サーバー名 ユーザー名 パスワード等 ) を格納すると アプリケーションのセキュリティに影響を及ぼす事が有る データベースへのアクセスを制御する方法と仕ては Windows オートメーション ( 統合セキュリティとも呼ばれる ) を使用する方が安全で有る ADO.NET コマンドオブジェクト アダプタを使用して データソース内のレコードの読み取り 追加 更新 削除が可能で有る 各操作を何の様に行うかを指定する為に アダプタは次の 4 つのプロパティをサポートして居る SelectCommand: データストアから行を取得するコマンドの参照 InsertCommand: データストアに行を挿入するコマンドの参照 UpdateCommand: データストアの行を変更するコマンドの参照 DeleteCommand: データストアから行を削除するコマンドの参照 コマンドとは SQL ステートメントやストアドプロシージャ名を謂う プロパティ自体は オブジェクトで有る プロパティは SqlCommand OleDbCommand OdbcCommand 又は OracleCommand の孰れかのクラスのインスタンスで有る 此等のオブジェクトは SQL ステートメントやストアドプロシージャへの参照を含む CommandText プロパティをサポートして居る -3-
コマンドクラスは 接続クラスと一致する必要が有る 例えば SqlConnection オブジェクトを使用して SQL Server と通信して居る場合は SqlCommand クラスから派生したコマンドを使用する必要が有る コマンドオブジェクトのテキストは明示的に設定出来るが 必ずしも設定する必要は無い 多くの場合は Visual Studio に依って必要な SQL ステートメントが生成される 亦 UpdateCommand InsertCommand 又は DeleteCommand オブジェクトが指定されて居ない場合は 実行時にアダプタが適切な SQL ステートメントを自動的に生成する 詳細に付いては コマンドの自動生成 を参照され度い 但し デザイン時や実行時にコマンドオブジェクトを操作する事で コマンドの実行をより直接的に制御出来る 例えば SelectCommand オブジェクトに関連付けられたコマンドを実行の直前に作成したり変更したり出来る データアダプタに依存せずに コマンドを自分で実行する事も出来る 此れに依り データベース定義の設定や変更に使用するコマンド等 任意の SQL コマンドをデータアダプタを通して渡す事が出来る 亦 レコードセットを返さないストアドプロシージャを直接呼び出す事も出来る 例えば データベースに対してユーザーの入力が適切か何うかを確認するストアドプロシージャ等で有る 詳細に付いては コマンドの実行 を参照され度い セキュリティに関するメモ :CommandType プロパティを Text に設定したデータコマンドを使用する時は クライアントから送信された情報をデータベースに渡す前に 其の情報を充分にチェックする必要が有る 悪意の有るユーザーが 承認無しでデータベースにアクセスしたり データベースを破壊したりする目的で 変更した SQL ステートメントや追加の SQL ステートメントの送信 ( 埋め込み ) を試みる場合が有る ユーザーの入力をデータベースに転送する前に 其の情報が有効で有る事を常に検証する必要が有る 出来る限り 常にパラメータ化されたクエリやストアドプロシージャを使用する事を推奨する 詳細に付いては スクリプトによる攻略の概要 を参照され度い コマンドパラメータ 通常 データアダプタ内のコマンドは パラメータドリブンで有る 例えば SelectCommand プロパティに対するコマンドは 多くの場合 WHERE 句にパラメータを持ち データベースから何のレコードを取得するかを実行時に指定出来る様に成って居る 其他のコマンドでは パラメータを使用して レコードに書き込むデータや データベース内の何のレコードを更新するか等の情報を実行時に渡す事が出来る データアダプタでのパラメータの使い方の詳細に付いては データアダプタコマンドのパラメータ を参照され度い データアダプタに依る読み取りと更新 データアダプタの主要な目的は データストアとデータセットの間でデータを交換する事で有る アダプタは 此の両者の間でデータを移動する為に固有のメソッドをサポートして居る データを読み取る丈で更新しない場合には データをデータセットに格納する必要は無い 其の代わりに データベースからアプリケーションに直接読み込む事が出来る 詳細に付いては 後の 読み取り専用データ を参照され度い データアダプタを使用して次の事が出来る データストアの行をデータセット内の対応するデータテーブルに取得する 行をデータセットに取得するには データアダプタオブジェクト ( SqlDataAdapter OleDbDataAdapter OdbcDataAdapter 又は OracleDataAdapter) に対して Fill メソッドを使用する Fill メソッドを呼び出すと データストアに SQL SELECT ステートメントが送信される -4-
データセットテーブルに加えられた変更を対応するデータストアに送信する データセットのデータセットテーブルをデータストアに送信するには アダプタの Update メソッドを使用する 此のメソッドを呼び出すと 対象のレコードを新しく作成するか 変更するか 削除するかに応じて 必要な SQL INSERT UPDATE 又は DELETE ステートメントが実行される データアダプタを使用して更新を実行する方法の詳細に付いては DataAdapter に依るデータソースの更新 を参照され度い 読み取り専用データ クエリ結果を使用して逐次読み取り専用でデータを渡す必要が有る場合は データセットを設定する代わりに データリーダーオブジェクトを使用出来る データリーダーオブジェクトは データソースからデータをフェッチし 直接アプリケーションに渡す 一般に データリーダーオブジェクトは データをデータセットにキャッシュする必要が無い時に データに対して読み取り専用で前方而巳のアクセスを行う為に使用される 但し データアダプタ自体は データセットにデータを格納する時にデータリーダーオブジェクトを使用する 読み取り専用アクセスの例と仕ては データベース情報を表示する Web フォームページが有る Web フォームページはラウンドトリップ毎に再作成される為 多くの場合 データをデータセットに格納しても意味が無い Visual Studio には 4 つのデータリーダーオブジェクト (SqlDataReader OleDbDataReader OdbcDataReader OracleDataReader) が用意されて居る 読み取り専用アクセスを効率良く実行する為のデータリーダーオブジェクトの使い方の詳細に付いては DataReader の使用 を参照され度い テーブル割り当て Visual Studio ツールを使用してデータベーステーブルからデータセットを生成した場合 既定では データセット内のテーブル名と列名がデータベース内の名前と同じに成る 併し 此れでは都合が悪い場合も有る 例えば データベースで使用されて居る名前が簡潔 又は 冗長過ぎる場合や 名前が外国語で表記されて居る場合等で有る 亦 既存のスキーマで作業して居る場合は スキーマで定義された名前がデータベースで使用されて居る名前と一致しない事も有る 従って データベース内の名前とデータセット内の名前が一致して居る必要は無い 其の代わりに データセットコマンドで新しいテーブル名や列名を作成して データベースで使用されて居る名前に関連付ける事が出来る アダプタは TableMappings コレクションを使用して データセットの構造 ( データテーブルやデータ列 ) とデータストアの構造 ( テーブルや列 ) との間の対応を維持する テーブル割り当ての詳細に付いては 後の データアダプタでのテーブル割り当て を参照され度い データアダプタでのテーブル割り当て データアダプタがデータソースからデータを読み取る場合は テーブル割り当てを使用して 対応するデータセットテーブルの何処にデータを格納するかを決定する 此の割り当ては ソース内の列の名前をデータセットテーブル内の列の名前にリンクして居る 例えば データソース内の au_id と謂う列の情報がデータセットテーブル内の author_id_number と謂う列に属して居る様な場合が考えられる 以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在も.NET Framework データプロバイダの主要なコンポーネントだが TableAdapter はデザイナで生成されるコンポーネントで アプリケーションとデータベースの間でデータを移動する処理を簡略化する TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い Visual Studio ツールを使用してデータソースの情報からデータセットを生成した場合 既定では デ -5-
ータセットの要素の名前は データソースでの名前と同じに成る 但し 下記の様に データソース内の名前とデータセット内の名前が一致しない場合も有る 異なる名前を使用する既存のスキーマからデータセットが生成された場合 使い易さ 読み易さ 外国語との間の変換 又は 其他の理由から データセット内のデータ要素名を変更する必要が有る場合 アダプタからデータセットを生成する時に 型指定されたデータメンバの名前を制御する場合 テーブル割り当ての構造 テーブル割り当ては アダプタの TableMappings プロパティに依って確立される 此れは DataTableMapping 型の項目のコレクションで有る 割り当てるテーブルのセット夫々れに付いて 1 つの DataTableMapping オブジェクトが有る 通常 アダプタは 1 つのソーステーブルと 1 つのデータセットテーブル丈に関連付けられる為 此の項目は 1 つしか無い 但し ストアドプロシージャは複数の行セットを返す場合が有る 其の場合 2 番目以降のテーブルは TableMappings コレクションの 2 番目以降の割り当てを使用して割り当てられる 夫々れの割り当て項目には データソーステーブルやデータセットテーブルを識別するプロパティ 及び 実際の割り当てを表す項目を含む ColumnMappings プロパティが含まれる テーブル割り当ての動作 データアダプタの Fill メソッドを呼び出すと アダプタは 以下のプロセスを実行して データセット内の何処にデータを書き込むかを決定する 1.TableMappings オブジェクト内で各ソース列名を探す 2. ソース列名が見付かれば データセットテーブル内の対応する列の一致する ( 関連付けられた ) 名前を取得する 3. 手順 2 で取得した名前を使用して ソース列のデータを対応するデータセット列に書き込む 様々な条件に於いて アダプタが上記のプロセスを実行出来ない場合が有る 主要な物は 下記の 2 つで有る ソース列に対して割り当てが見付からない場合 此の原因と仕ては TableMappings プロパティに何も定義されて居ないか 特定の列が割り当てられて居ない事が考えられる 書き込む列が TableMappings プロパティに割り当てられて居るか何うかに関係無く 其の列がデータセットのスキーマに定義されて居ない場合 アダプタには 此の孰れかの状況に当て嵌る場合に何の様に処理するかを指定する為の 2 つのプロパティが用意されて居る 此等の状況が発生してもアダプタはデータセットにデータを格納出来る為 必ずしもエラーでは無い MissingMappingAction プロパティは マップが見付からない場合にアダプタが何の様に処理するかを指定する為に使用する 次の設定が可能で有る Passthrough: アダプタは 列のデータを同じ名前のデータセット列に格納する 同じ名前のデータセット列が無い場合 動作は下記の MissingSchemaAction の設定に依存する -6-
Ignore: 適切に割り当てられて居ない列は データセットに読み込まれない Error: エラーを発生させる MissingSchemaAction プロパティでは アダプタがデータセットのスキーマに定義されて居ない列にデータを書き込もうと仕た時の処理を指定する 次の値を使用出来る Add: テーブル 又は 列が スキーマ 及び データセットに追加される AddWithKey: テーブル 又は 列が 主キーに関する情報と共に データセット 及び スキーマに追加される Ignore: データセットスキーマに表されて居ないテーブルや列はデータセットに追加されない Error: エラーを発生させる 一般には 両方のプロパティを組み合わせて設定する事に依り アプリケーション固有のニーズを満足させる MissingMappingAction プロパティを Passthrough に MissingSchemaAction プロパティを Add に設定すると データセットでテーブル名や列名が自動的にソースから複製される 逆に データセットスキーマが厳密に定義されたアプリケーションでは エラーのチェックを指定出来る 其の様な場合 データセット内の格納先の列を明確に定義せずにソースからデータを取得すると ビジネスルールの違反等のエラーに成る可能性が有る スキーマに明示的に定義したデータや TableMappings プロパティで割り当てられて居るデータ丈をデータセットに読み込む場合は Ignore を指定する 此れは データセット内で必要な数よりも多い列を返すストアドプロシージャや SQL ステートメントをアダプタが呼び出す場合に便利で有る データアダプタコマンドのパラメータ 多くの場合 SelectCommand InsertCommand UpdateCommand DeleteCommand オブジェクトの CommandText プロパティに定義されるデータアダプタのコマンドには パラメータが有る 実行時に パラメータを使用して コマンドが表す SQL ステートメントやストアドプロシージャに値を渡す 以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在でも.NET Framework データプロバイダのメインコンポーネントだが デザイナに依って生成されるコンポーネントで有る TableAdapter を使うと アプリケーションとデータベース間でデータを遣り取りするプロセスは簡略化される TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い パラメータは 2 つのコンテキストで使用される 選択パラメータ : 実際のアプリケーションでは データベース内のデータのサブセット丈をフェッチする事が頻繁に有る 其の為には 実行時に取得する選択基準のパラメータを持つ WHERE 句を含む SQL ステートメントやストアドプロシージャを使用する 亦 レコードの更新や削除をする時には 変更対象のレコードを指定する WHERE 句を使用する WHERE 句で使用される値は 通常は実行時に取得される 更新パラメータ : 既存のレコードを更新する場合 又は 新しいレコードを挿入する場合に 変更するレコードや新しいレコードの列の値を実行時に確立する 亦 オプティミスティック同時実行制御のチェック中に使用される値は パラメータを使用して確立される -7-
Oracle では SQL ステートメントやストアドプロシージャで名前付きパラメータを使用する場合 パラメータ名の前にコロン ( : ) を付ける必要が有る 但し コード内の他の場所に有る名前付きパラメータを参照する場合 (Add を呼び出す場合等 ) には 名前付きパラメータの前にコロンは付けない データプロバイダが自動的にコロンを追加する 詳細に付いては OracleParameter クラス を参照され度い 選択パラメータ データセットに格納するレコードを選択する時は 多くの場合 WHERE 句にパラメータを含めて フェッチするレコードを実行時に指定出来る様にする 例えば ユーザーが特定のタイトルキーワードを Web ページに入力して本のデータベースを検索するとする 其れを可能にするには 次に示す様な SQL ステートメントを SelectCommand の CommandText プロパティと仕て指定する パラメータはプレースホルダ ( 疑問符 :? ) 又は 名前付きパラメータ変数に依って示される OleDbCommand オブジェクトや OdbcCommand オブジェクトを使用したクエリのパラメータには 疑問符 (? ) を使用する SqlCommand オブジェクトを使用したクエリには アットマーク (@) で始まる名前付きパラメータを使用する OracleCommand オブジェクトの場合は コロン ( : ) で始まる名前付きパラメータを使用する プレースホルダを使用したクエリの例を次に示す (Access MySQL 等の場合 ) SELECT BookId, Title, Author, Price from BOOKS WHERE (Title LIKE?) SqlCommand 名前付きパラメータを使用するクエリの例を次に示す (SQL Server 7.0 以降の場合 ) SELECT BookId, Title, Author, Price from BOOKS WHERE (Title LIKE @title) OracleCommand 名前付きパラメータを使用するクエリの例を次に示す (Oracle の場合 ) SELECT BookId, Title, Author, Price from BOOKS WHERE (Title LIKE :title) アプリケーションで ユーザーにタイトルキーワードの入力を要求する 然して パラメータの値を設定してコマンドを実行する ルックアップテーブルを設定する場合等 データベーステーブル全体の内容を取得する必要が有る場合も有る 併し一般には アプリケーションの効率を高める為 必要なデータ丈をフェッチする Visual Studio では クエリビルダを使用してパラメータを持つ SQL ステートメントを作成出来る サーバーエクスプローラから要素をドラッグすると 可能な部分に付いては Visual Studio に依って自動的にパラメータが設定される 設定は手動で完成させる必要が有る 更新パラメータ アダプタの SelectCommand オブジェクトにパラメータ化されたコマンドが含まれるか何うかに関係無く UpdateCommand InsertCommand DeleteCommand の各プロパティに対するコマンドには常にパラメータが含まれる UpdateCommand プロパティや InsertCommand プロパティに対するコマンドでは データベース内で更新する総ての列に対してパラメータが必要で有る 亦 UpdateCommand ステートメントや DeleteCommand ステートメントでは 多くの SelectCommand オブジェクトと同様に 更新するレコードを識別する為のパラメータ化された WHERE 句が必要で有る -8-
ユーザーが本を購入出来るアプリケーションを考えて観る事にする ユーザーは 買い物をする間 買い物籠を保持するが 此れは データテーブルと仕て実装される ShoppingCart テーブルに於いて ユーザーは購入する夫々れの本に対するレコードを保持する 此のレコードには 書籍 ID と顧客 ID が含まれ 買い物籠レコードのキーと仕て使用される ユーザーが買い物籠に本を追加すると アプリケーションは SQL INSERT ステートメントを呼び出す アダプタでのステートメントの構文は次の様に成る INSERT INTO ShoppingCart (BookId, CustId, Quantity) Values (?,?,?) 3 つの疑問符 (? ) は 顧客 ID 書籍 ID 及び 数量の値を実行時に取得するパラメータのプレースホルダを示して居る 名前付きパラメータを使用して居る場合は 同じクエリが次の様に成る INSERT INTO ShoppingCart (BookId, CustId, Quantity) Values (@bookid, @custid, @quantity) ユーザーが買い物カゴ内の項目を変更する場合 ( 例えば 数量の変更等 ) アプリケーションは SQL UPDATE ステートメントを呼び出す 此のステートメントの構文は次の様に成る UPDATE ShoppingCart SET (BookId =?, CustId =?, Quantity =?) WHERE (BookId =? AND CustId =?) 亦 名前付きパラメータを使用して居る場合は次の様に成る UPDATE ShoppingCart SET (BookId = @bookid, CustId = @custid, Quantity = @quantity) WHERE (BookId = @bookid AND CustId = @custid) 此のステートメントに於いて SET 句のパラメータには変更するレコードの新しい値が入る WHERE 句のパラメータは 何のレコードを更新するかを識別する物で有り レコードの元の値が入る ユーザーは 買い物籠から項目を削除する事も出来る 其の場合 パラメータのプレースホルダを使用して居る時は アプリケーションは次の様な構文で SQL DELETE ステートメントを呼び出す DELETE FROM ShoppingCart WHERE (BookId =? AND CustId =?) 名前付きパラメータを使用して居る時は 次の様に成る DELETE FROM ShoppingCart WHERE (BookId = @bookid AND CustId = @custid) パラメータコレクションとパラメータオブジェクト 実行時にパラメータの値を渡す事が出来る様に データアダプタの 4 つのコマンドオブジェクトは夫々れ Parameters プロパティをサポートして居る 此のプロパティには ステートメント内のプレースホルダと一対一で対応する各パラメータオブジェクトのコレクションが含まれる -9-
各データアダプタに対応するパラメータコレクションを次の表に示す データアダプタ SqlDataAdapter OleDbDataAdapter OdbcDataAdapter OracleDataAdapter パラメータコレクション SqlParameterCollection OleDbParameterCollection OdbcParameterCollection OracleParameterCollection Oracle では SQL ステートメントやストアドプロシージャで名前付きパラメータを使用する場合 パラメータ名の前にコロン ( : ) を付ける必要が有る 但し コード内の他の場所に有る名前付きパラメータを参照する場合 (Add を呼び出す場合等 ) には 名前付きパラメータの前にコロンは付けない.NET Framework Oracle 用データプロバイダが自動的にコロンを追加する パラメータコレクションを使用する事で 実行時の値に依って SQL コマンドの文字列を手動で構築する手間が省け 更に パラメータで型チェックが出来ると謂う利点も有る データアダプタ構成ウィザードを使用してアダプタを設定する場合は 4 つのアダプタコマンド総てに対してパラメータコレクションが自動的にセットアップされ 設定される サーバーエクスプローラからフォームやコンポーネントに要素をドラッグすると Visual Studio は以下の設定を実行する デザイナにテーブルや列をドラッグした場合 Visual Studio はパラメータの無い SelectCommand オブジェクト ( 詰まり SQL SELECT ステートメント ) と パラメータ化された UpdateCommand InsertCommand DeleteCommand の各オブジェクトを生成する SelectCommand オブジェクトステートメントにパラメータを含める場合は 手動で設定出来る デザイナにストアドプロシージャをドラッグした場合 Visual Studio は ストアドプロシージャの必要に応じてパラメータを持つ SelectCommand オブジェクトを生成する 但し UpdateCommand InsertCommand DeleteCommand の各オブジェクトが必要な場合は 各オブジェクトをパラメータと共に自分で設定する必要が有る 一般に アダプタに対してパラメータ化されたクエリを作成する場合は データアダプタ構成ウィザードを使用する 但し 必要な場合は [ プロパティ ] ウィンドウを使用してパラメータを手動で設定する事も出来る パラメータコレクションの構造 コマンドパラメータコレクション内の項目は 対応するコマンドオブジェクトに必要なパラメータと一対一で対応して居る コマンドオブジェクトが SQL ステートメントで有る場合 コレクション内の項目はステートメント内のプレースホルダ ( 疑問符 :? ) に対応する 次の UPDATE ステートメントには 5 つのパラメータ項目のコレクションが必要で有る UPDATE ShoppingCart SET (BookId =?, CustId =?, Quantity =?) WHERE (BookId =? AND CustId =?) 名前付きパラメータを使用すると 同じステートメントが次の様に成る UPDATE ShoppingCart SET (BookId = @bookid, CustId = @custid, Quantity = @quantity) WHERE (BookId = @bookid AND CustId = @custid) コマンドオブジェクトがストアドプロシージャを参照する場合 コレクション内のパラメータ項目の数 -10-
は プロシージャ自体に依って決定される パラメータは SQL ステートメント内のプレースホルダと厳密に対応しない場合も有る ストアドプロシージャでは 名前付きパラメータも使用出来る 其の場合 コレクション内のパラメータの位置は重要では無い 其の代わり コレクション内の各パラメータ項目には ParameterName プロパティが有り 其れを使用してストアドプロシージャ内の対応するパラメータと一致させる パラメータコレクションを手動で設定する場合は ストアドプロシージャで何のパラメータが必要なのかを正確に理解して居る必要が有る 多くのストアドプロシージャは値を返す 其の場合 値はパラメータコレクション内でアプリケーションに返される為 其れを可能に仕て置く必要が有る 更に ストアドプロシージャには 複数の SQL ステートメントが含まれる場合が有り パラメータコレクションが プロシージャ内の総てのステートメントに渡される総ての値を反映する必要が有る ストアドプロシージャでパラメータに名前が付いて居ない場合 コレクション内の項目はコマンドで必要なパラメータと位置的に対応する コマンドがストアドプロシージャで有り 値を返す場合 コレクション内の最初の項目 ( 項目 0) は 此の戻り値の為に確保される 従って 夫々れのパラメータオブジェクトは コレクション内のインデックス位置に依って参照出来る 但し パラメータオブジェクトは パラメータを其の順序と関係無く参照する為の ParameterName プロパティもサポートして居る 例えば コレクションの 2 番目のパラメータが Title_Keyword と謂う名前で有る場合 次の 2 つのステートメントは等しく成る Visual Basic ' ワイルドカードで囲んだキーワード titlekeyword = "%" & txttitlekeyword.text & "%" OleDbDataAdapter1.SelectCommand.Parameters(1).Value = titlekeyword OleDbDataAdapter1.SelectCommand.Parameters("Title_Keyword").Value = titlekeyword C# // ワイルドカードで囲んだキーワード string titlekeyword = "%" + txttitlekeyword.text + "%"; this.oledbdataadapter1.selectcommand.parameters[1].value = titlekeyword; this.oledbdataadapter1.selectcommand.parameters["title_keyword"].value = titlekeyword; 一般に インデックス値でパラメータを参照するよりも パラメータ名を使用する方がプログラミング手法と仕ては優れて居る 何故なら パラメータの数が変更された時の必要な保守作業が減り 亦 ストアドプロシージャが値を返すか何うかを覚えて置く必要が無いからで有る パラメータを名前で参照する場合は インデックス値で参照する場合よりも 僅かにオーバーヘッドが増えるが 此れはプログラミングの簡単さとアプリケーションの保守性に依って相殺される パラメータ値の確立 パラメータの値を確立するには 次の 2 つの方法が有る パラメータの Value プロパティを明示的に設定する パラメータをデータセットテーブルの列に割り当て 必要な時にデータ行から値を抽出する事が出来る様にする データセットに値を格納する場合やコマンドを呼び出す場合 ( 詰まり 選択パラメータの場合 ) パラメータの値を明示的に設定する 例えば 前に示した本を検索する例に於いて ユーザーがタイトルキーワードを入力する為のテキストボックスを アプリケーションに追加する事も出来る 其の場合 パ -11-
ラメータの値をテキストボックスのテキストに明示的に設定してから アダプタの Fill メソッドを呼び出す 此れを行うコードは次の様に成る 此のコードは テキストボックスの内容をパラメータと仕て確立してから データセットに値を格納する Visual Basic ' ワイルドカードで囲んだキーワード titlekeyword = "%" & txttitlekeyword.text & "%" OleDbDataAdapter1.SelectCommand.Parameters("Title_Keyword").Value = titlekeyword OleDbDataAdapter1.Fill(dsAuthors1) C# // ワイルドカードで囲んだキーワード titlekeyword = "%" + txttitlekeyword.text + "%"; this.oledbdataadapter1.selectcommand.parameters["title_keyword"].value = titlekeyword; this.oledbdataadapter1.fill(dsauthors1); 割り当てられたパラメータ値は 更新時に使用される アダプタの Update メソッドを呼び出すと メソッドは データセットテーブル内の各レコードに対して個別に適切な更新 ( 更新 挿入 削除 ) を行う 其の場合 パラメータの値は データセットレコード内の列と仕て既に存在して居る 例えば 更新プロセスがデータベーステーブル内の新しいレコード ( データベースで INSERT ステートメントを呼び出す必要の有るレコード ) に達した場合 INSERT ステートメントの VALUE 句に対する値をレコードから直接読み取る事が出来る 此等は 一般的なシナリオだが 其れが総てでは無い ストアドプロシージャは out パラメータを使用して 又は プロシージャの戻り値を使用してデータを返す場合が有る 其の様な場合 返された値をデータセットテーブルの列に割り当てる必要が有る 更新パラメータも明示的に設定する事が可能で有る アダプタは 行が更新される度に呼び出される RowUpdating イベントをサポートして居る 此のイベントのハンドラを作成して 其の中でパラメータ値を設定出来る 其れに依り パラメータ値を精密に制御出来 パラメータ値の作成な何のプロセスをデータベースレコードに書き込む前に動的に実行出来る -12-
コマンドの使用 此のセクションの内容 コマンドの実行 (13 頁 ) ADO.NET の Command オブジェクトと 其れを使用してデータソースに対してクエリやコマンドを実行する方法に付いて説明する コマンドに依るストアドプロシージャの使用 (14 頁 ) Command オブジェクトを使用してストアドプロシージャを呼び出す方法に付いて説明する パラメータ値の受け渡しに付いての情報も含まれる コマンドの自動生成 (20 頁 ) CommandBuilder を使用して 単一テーブルを対象とする SELECT コマンドを持つ DataAdapter に対応して INSERT UPDATE DELETE の各コマンドを自動的に生成する方法に付いて説明する データベースからの単一の値の取得 (23 頁 ) Command オブジェクトを使用してデータベースクエリから単一の値を返す方法に付いて説明する コマンドの実行 Command オブジェクトは 目的のアクションを実行する為に使用出来る様々な Execute メソッドを公開する 結果をデータストリームと仕て返す時は ExecuteReader を使用して DataReader オブジェクトを返す シングルトン値を返すには ExecuteScalar を使用する 行を返さないコマンドを実行するには ExecuteNonQuery を使用する ストアドプロシージャと共に Command オブジェクトを使用する時は Command オブジェクトの CommandType プロパティを StoredProcedure に設定する事も出来る StoredProcedure の CommandType と共に Command の Parameters プロパティを使用して入力パラメータ 出力パラメータ 及び 戻り値にアクセス出来る Parameters プロパティには Execute メソッドが呼び出されたか何うかに関係無くアクセス出来る 併し ExecuteReader を呼び出す時は DataReader が終了する迄は 戻り値や出力パラメータにアクセス出来ない 次のコード例では SQL Server の Northwind サンプルデータベースから カテゴリのリストを返す様に SqlCommand オブジェクトを作成する方法を示す Visual Basic Dim command As SqlCommand = New SqlCommand( _ "SELECT CategoryID, CategoryName FROM dbo.categories", nwindconn) C# SqlCommand command = new SqlCommand( "SELECT CategoryID, CategoryName FROM dbo.categories", nwindconn); 上記で 変数 nwindconn は 有効な SqlConnection オブジェクトとする コマンドのパフォーマンスカウンタ.NET Framework Data Provider for SQL Server には 失敗したコマンド実行に関連して断続的に発生する問題を検出出来るパフォーマンスカウンタが追加されて居る パフォーマンスモニタの中で.NET CLR Data パフォーマンスオブジェクト内に有る SqlClient: Total # failed commands (SqlClient: 失敗したコマンドの合計数 ) カウンタにアクセスすると 何等かの理由で失敗したコマンド実行の合計数を確認出来る -13-
.NET Framework Data Provider for SQL Server のパフォーマンスカウンタを ASP.NET アプリケーションと共に使用する場合は _Global インスタンス而巳使用する事を推奨する 従って パフォーマンスカウンタが返す値は 総ての ASP.NET アプリケーションのカウンタ値の合計と成る コマンドに依るストアドプロシージャの使用 ストアドプロシージャは データドリブンのアプリケーションに多くの利点を提供する ストアドプロシージャを使用すると データベースの操作を単一のコマンドにカプセル化し 最大のパフォーマンスが得られる様に最適化し 更に追加のセキュリティ機能を使用して セキュリティを強化する事が出来る ストアドプロシージャは ストアドプロシージャ名の後にパラメータ引数を記述して SQL ステートメントと仕て渡す丈で呼び出す事が出来るが ADO.NET の DbCommand オブジェクトの Parameters コレクションを使用すると ストアドプロシージャをより明示的に定義出来 出力パラメータや戻り値にもアクセス出来る ストアドプロシージャを呼び出すには Command オブジェクトの CommandType を StoredProcedure に設定する 次の例に示す様に CommandType を StoredProcedure に設定した後 Parameters コレクションを使用してパラメータを定義出来る OdbcCommand では ストアドプロシージャを呼び出す時に ODBC CALL 構文全体を入力する必要が有る Visual Basic ' 変数 connection は 有効な SqlConnection オブジェクトとする Dim salescommand As SqlCommand = New SqlCommand( "SalesByCategory", connection ) salescommand.commandtype = CommandType.StoredProcedure Dim parameter As SqlParameter = salescommand.parameters.add( _ "@CategoryName", SqlDbType.NVarChar, 15) parameter.value = "Beverages" connection.open( ) Dim reader As SqlDataReader = salescommand.executereader( ) Console.WriteLine("{0}, {1}", reader.getname(0), reader.getname(1)) Do While reader.read( ) Console.WriteLine("{0}, ${1}", reader.getstring(0), reader.getdecimal(1)) Loop reader.close( ) connection.close( ) C# // 変数 connection は 有効な SqlConnection オブジェクトとする SqlCommand salescommand = new SqlCommand("SalesByCategory", connection); salescommand.commandtype = CommandType.StoredProcedure; SqlParameter parameter = salescommand.parameters.add( "@CategoryName", SqlDbType.NVarChar, 15); parameter.value = "Beverages"; -14-
connection.open( ); SqlDataReader reader = salescommand.executereader( ); Console.WriteLine( "{0}, {1}", reader.getname(0), reader.getname(1)); while (reader.read( )) { Console.WriteLine("{0}, ${1}", reader.getstring(0), reader.getdecimal(1)); } reader.close( ); connection.close( ); Parameter オブジェクトを作成するには Parameter コンストラクタを使用するか 又は Command の Parameters コレクションの Add メソッドを呼び出す Parameters.Add は 入力と仕てコンストラクタ引数 又は 既存の Parameter オブジェクトを受け取る Parameter の Value を null 参照に設定する時は DBNull.Value を使用する Input パラメータ以外のパラメータに対して ParameterDirection プロパティを設定し パラメータタイプが InputOutput Output ReturnValue の内の孰れで有るかを指定する必要が有る 様々なプロバイダに付いて Input Output ReturnValue の各パラメータの作成に関する違いを次の例に示す SqlClient の例 Visual Basic ' 変数 connection は 有効な SqlConnection オブジェクトとする Dim command As SqlCommand = New SqlCommand("SampleProc", connection) command.commandtype = CommandType.StoredProcedure Dim parameter As SqlParameter = command.parameters.add( _ "RETURN_VALUE", SqlDbType.Int) parameter.direction = ParameterDirection.ReturnValue parameter = command.parameters.add( "@InputParm", SqlDbType.NVarChar, 12) parameter.value = "Sample Value" parameter = command.parameters.add( "@OutputParm", SqlDbType.NVarChar, 28) parameter.direction = ParameterDirection.Output connection.open( ) Dim reader As SqlDataReader = command.executereader( ) Console.WriteLine( "{0}, {1}", reader.getname(0), reader.getname(1)) Do While reader.read( ) Console.WriteLine( "{0}, {1}", reader.getint32(0), reader.getstring(1)) Loop reader.close( ) connection.close( ) -15-
Console.WriteLine( " @OutputParm: {0}", command.parameters("@outputparm").value) Console.WriteLine( "RETURN_VALUE: {0}", command.parameters("return_value").value) C# // 変数 connection は 有効な SqlConnection オブジェクトとする SqlCommand command = new SqlCommand("SampleProc", connection); command.commandtype = CommandType.StoredProcedure; SqlParameter parameter = command.parameters.add("return_value", SqlDbType.Int); parameter.direction = ParameterDirection.ReturnValue; parameter = command.parameters.add("@inputparm", SqlDbType.NVarChar, 12); parameter.value = "Sample Value"; parameter = command.parameters.add("@outputparm", SqlDbType.NVarChar, 28); parameter.direction = ParameterDirection.Output; connection.open( ); SqlDataReader reader = command.executereader( ); Console.WriteLine("{0}, {1}", reader.getname(0), reader.getname(1)); while (reader.read( )) { Console.WriteLine("{0}, {1}", reader.getint32(0), reader.getstring(1)); } reader.close( ); connection.close( ); Console.WriteLine(" @OutputParm: {0}", command.parameters["@outputparm"].value); Console.WriteLine("RETURN_VALUE: {0}", command.parameters["return_value"].value); OleDb の例 Visual Basic ' 変数 connection は 有効な OleDbConnection オブジェクトとする Dim command As OleDbCommand = New OleDbCommand( "SampleProc", connection) command.commandtype = CommandType.StoredProcedure Dim parameter As OleDbParameter = command.parameters.add( _ "RETURN_VALUE", OleDbType.Integer) parameter.direction = ParameterDirection.ReturnValue parameter = command.parameters.add( "@InputParm", OleDbType.VarChar, 12) parameter.value = "Sample Value" parameter = command.parameters.add( "@OutputParm", OleDbType.VarChar, 28) parameter.direction = ParameterDirection.Output connection.open( ) Dim reader As OleDbDataReader = command.executereader( ) -16-
Console.WriteLine("{0}, {1}", reader.getname(0), reader.getname(1)) Do While reader.read( ) Console.WriteLine("{0}, {1}", reader.getint32(0), reader.getstring(1)) Loop reader.close( ) connection.close( ) Console.WriteLine(" @OutputParm: {0}", command.parameters("@outputparm").value) Console.WriteLine("RETURN_VALUE: {0}", command.parameters("return_value").value) C# // 変数 connection は 有効な OleDbConnection オブジェクトとする OleDbCommand command = new OleDbCommand("SampleProc", connection); command.commandtype = CommandType.StoredProcedure; OleDbParameter parameter = command.parameters.add( "RETURN_VALUE", OleDbType.Integer); parameter.direction = ParameterDirection.ReturnValue; parameter = command.parameters.add("@inputparm", OleDbType.VarChar, 12); parameter.value = "Sample Value"; parameter = command.parameters.add("@outputparm", OleDbType.VarChar, 28); parameter.direction = ParameterDirection.Output; connection.open( ); OleDbDataReader reader = command.executereader( ); Console.WriteLine("{0}, {1}", reader.getname(0), reader.getname(1)); while (reader.read( )) { Console.WriteLine("{0}, {1}", reader.getint32(0), reader.getstring(1)); } reader.close( ); connection.close( ); Console.WriteLine(" @OutputParm: {0}", command.parameters["@outputparm"].value); Console.WriteLine("RETURN_VALUE: {0}", command.parameters["return_value"].value); Odbc の例 Visual Basic ' 変数 connection は 有効な OdbcConnection オブジェクトとする Dim command As OdbcCommand = New OdbcCommand( _ "{? = CALL SampleProc(?,?) }", connection) command.commandtype = CommandType.StoredProcedure Dim parameter As OdbcParameter = command.parameters.add( _ "RETURN_VALUE", OdbcType.Int) parameter.direction = ParameterDirection.ReturnValue -17-
parameter = command.parameters.add( "@InputParm", OdbcType.VarChar, 12) parameter.value = "Sample Value" parameter = command.parameters.add( "@OutputParm", OdbcType.VarChar, 28) parameter.direction = ParameterDirection.Output connection.open( ) Dim reader As OdbcDataReader = command.executereader( ) Console.WriteLine("{0}, {1}", reader.getname(0), reader.getname(1)) Do While reader.read( ) Console.WriteLine("{0}, {1}", reader.getint32(0), reader.getstring(1)) Loop reader.close( ) connection.close( ) Console.WriteLine(" @OutputParm: {0}", command.parameters("@outputparm").value) Console.WriteLine("RETURN_VALUE: {0}", command.parameters("return_value").value) C# // 変数 connection は 有効な OdbcConnection オブジェクトとする OdbcCommand command = new OdbcCommand( _ "{? = CALL SampleProc(?,?) }", connection); command.commandtype = CommandType.StoredProcedure; OdbcParameter parameter = command.parameters.add( _ "RETURN_VALUE", OdbcType.Int); parameter.direction = ParameterDirection.ReturnValue; parameter = command.parameters.add( "@InputParm", OdbcType.VarChar, 12); parameter.value = "Sample Value"; parameter = command.parameters.add( "@OutputParm", OdbcType.VarChar, 28); parameter.direction = ParameterDirection.Output; connection.open( ); OdbcDataReader reader = command.executereader( ); Console.WriteLine("{0}, {1}", reader.getname(0), reader.getname(1)); while (reader.read( )) { Console.WriteLine( _ "{0}, {1}", reader.getint32(0), reader.getstring(1)); } reader.close( ); connection.close( ); Console.WriteLine(" @OutputParm: {0}", command.parameters["@outputparm"].value); Console.WriteLine("RETURN_VALUE: {0}", command.parameters["return_value"].value); -18-
SqlCommand に依るパラメータの使用 SqlCommand でパラメータを使用する時は Parameters コレクションに追加したパラメータの名前が ストアドプロシージャ内のパラメータマーカーの名前と一致して居る必要が有る.NET Framework Data Provider for SQL Server は ストアドプロシージャ内のパラメータを名前付きのパラメータと看做して 一致するパラメータマーカーを検索する.NET Framework Data Provider for SQL Server は SQL ステートメントやストアドプロシージャにパラメータを渡す場合の疑問符 (? ) プレースホルダをサポートして居ない 此の場合は 次の例に示す様に名前付きのパラメータを使用する必要が有る 此の例では @CustomerID が名前付きのパラメータで有る SELECT * FROM Customers WHERE CustomerID = @CustomerID OleDbCommand 又は OdbcCommand に依るパラメータの使用 OleDbCommand 又は OdbcCommand でパラメータを使用する時は Parameters コレクションにパラメータが追加されて居る順序が ストアドプロシージャ内でパラメータが定義されて居る順序と一致して居る必要が有る.NET Framework Data Provider for OLE DB と.NET Framework Data Provider for ODBC は ストアドプロシージャ内のパラメータをプレースホルダと仕て処理し 順にパラメータ値を適用する 亦 戻り値パラメータは Parameters コレクションに最初に追加されたパラメータにする必要が有る OLE DB の.NET データプロバイダと ODBC の.NET データプロバイダは SQL ステートメントやストアドプロシージャにパラメータを渡す場合の名前付きのパラメータをサポートして居ない 此の場合は 次の例に示す様に疑問符 (? ) プレースホルダを使用する必要が有る SELECT * FROM Customers WHERE CustomerID =? 従って Parameters コレクションに Parameter オブジェクトを追加する順序は パラメータの疑問符 (? ) プレースホルダの位置と完全に対応して居る必要が有る パラメータ情報の派生 CommandBuilder クラスを使用してストアドプロシージャからパラメータを派生させる事が出来る SqlCommandBuilder クラスと OleDbCommandBuilder クラスは 孰れも静的メソッド DeriveParameters を提供する 此のメソッドは ストアドプロシージャから得られたパラメータ情報を使用して Command オブジェクトの Parameters コレクションを設定する DeriveParameters は Command の既存のパラメータ情報を上書きする パラメータ情報の派生には 情報のデータソースへの追加のトリップが必要で有る パラメータ情報がデザイン時に解って居る場合は パラメータを明示的に設定する事でアプリケーションのパフォーマンスを改善出来る CommandBuilder.DeriveParameters を使用して Command オブジェクトの Parameters コレクションを設定する方法を次のコード例に示す Visual Basic ' 変数 connection は 有効な SqlConnection オブジェクトとする Dim salescommand As SqlCommand = New SqlCommand( "Sales By Year", connection) salescommand.commandtype = CommandType.StoredProcedure -19-
connection.open( ) SqlCommandBuilder.DeriveParameters(salesCommand) connection.close( ) C# // 変数 connection は 有効な SqlConnection オブジェクトとする SqlCommand salescommand = new SqlCommand("Sales By Year", connection); salescommand.commandtype = CommandType.StoredProcedure; connection.open( ); SqlCommandBuilder.DeriveParameters(salesCommand); connection.close( ); コマンドの自動生成 SelectCommand プロパティが実行時に動的に指定される場合 例えばクエリツールを使用してユーザーの記述したクエリ構文を解釈する場合は 適切な InsertCommand UpdateCommand 又は DeleteCommand をデザイン時に指定する事は出来ない DataTable を単一データベーステーブルに割り当てたり 単一データベースから生成する場合は DbCommandBuilder オブジェクトを利用して自動的に DbDataAdapter の DeleteCommand InsertCommand UpdateCommand を生成出来る コマンドを自動的に生成する為の最低限の条件と仕て SelectCommand プロパティを設定する必要が有る SelectCommand プロパティで取得したテーブルスキーマに依って 自動的に生成される INSERT UPDATE DELETE の各ステートメントの構文が決定される DbCommandBuilder は INSERT UPDATE DELETE の各コマンドを生成する為に SelectCommand を実行する必要が有る 其の結果 データソースへの追加のトリップが必要に成る為 パフォーマンスが低下する可能性が有る 最適のパフォーマンスを実現するには 明示的にコマンドを指定し DbCommandBuilder を使用しない様にする SelectCommand は 少なく共 1 つの主キー 又は 一意の列を返す必要が有る 孰れも存在しない場合は InvalidOperation 例外が生成され コマンドは生成されない DataAdapter との関連付けが行われて居て DataAdapter の InsertCommand UpdateCommand DeleteCommand の各プロパティが null 参照で有る場合 DbCommandBuilder は自動的に此等のプロパティを生成する プロパティに対して既に Command が存在する場合は 既存の Command が使用される 複数のテーブルを結合して作成したデータベースビューは 単一データベーステーブルとは看做されない 此の場合は DbCommandBuilder を使用してコマンドを自動的に生成出来ない為 コマンドを明示的に指定する必要が有る DataSet に対する更新を元のデータソースに反映させるコマンドを明示的に設定する方法に付いては DataAdapter に依るデータソースの更新 を参照され度い 出力パラメータを DataSet の更新行に割り当てる事が必要な場合が有る 一般的なタスクの 1 つは データソースの自動的に生成された ID フィールド 又は タイムスタンプの値を取得する事で有る DbCommandBuilder は 既定では更新行の列に出力パラメータを割り当てない 其の場合は コマンドを明示的に指定する必要が有る 自動的に生成された ID フィールドを挿入行の列に割り当てる例に付いては ID 値 及び Autonumber 値の取得 を参照され度い コマンドの自動生成規則 コマンドの自動生成規則を次の表に示す -20-
コマンド InsertCommand UpdateCommand DeleteCommand 規則 RowState が Added に設定されて居るテーブル内の総ての行に対して データソースの行を挿入する 更新可能な総ての列に対して値を挿入する ( 但し ID 式 タイムスタンプ等の列は除く ) RowState が Modified に設定されて居るテーブルの総ての行に該当するデータソース側の行を更新する ID や式等の更新不可能な列を除く 総ての列の値を更新する データソースの列の値と該当行の主キー列の値が一致し 更にデータソースの其他の列が其の行の元の値と一致する総ての行を更新する 詳細に付いては 此の資料で後述する 更新と削除のオプティミスティック同時実行制御 を参照され度い RowState が Deleted に設定されて居るテーブルの総ての行に該当するデータソース側の行を削除する 列の値と其の行の主キー列の値が一致し 更にデータソースの其他の列が其の行の元の値と一致する総ての行を削除する 詳細に付いては 此の資料で後述する 更新と削除のオプティミスティック同時実行制御 を参照され度い 更新及び削除のオプティミスティック同時実行制御 UPDATE ステートメントや DELETE ステートメントに対するコマンドの自動生成ロジックは オプティミスティック同時実行制御に基づいて居る 此れは 詰まり 編集時にレコードがロックされず 他のユーザーやプロセスが其のレコードを何時でも変更出来る事を意味する レコードは SELECT ステートメントに依って返された後 UPDATE ステートメントや DELETE ステートメントの実行前に変更されて居る可能性も有る為 自動的に生成される UPDATE ステートメントや DELETE ステートメントには 元の総ての値を含み データソースから削除されて居ない行丈を更新する様に指定した WHERE 句が含まれる 此れに依り 新しいデータが上書きされるのを防ぐ 自動的に生成された更新コマンドが削除済み 又は DataSet に有る元の値が含まれて居ない行を更新し様とすると コマンドは何のレコードにも反映されずに DBConcurrencyException がスローされる 元の値とは関係無く UPDATE や DELETE を実行する場合は DataAdapter に明示的に UpdateCommand を設定し コマンドの自動生成は行わない コマンドの自動生成ロジックの制限事項 コマンドの自動生成には 次の制限事項が適用される リレーションシップの無いテーブルに限定コマンドの自動生成ロジックでは データソースの他のテーブルへのリレーションシップを考慮せずに 独立したテーブルを対象と仕て INSERT UPDATE DELETE の各ステートメントを生成する 其の結果 Update を呼び出してデータベースの外部キー制約に関係する列に対する変更を発行すると エラーが発生する場合が有る 此の様な例外を防ぐには 外部キー制約に関係する列の更新には DbCommandBuilder を使用せず 更新操作を実行するステートメントを明示的に指定する テーブル名と列名列名やテーブル名にスペース ピリオド (. ) 疑問符 (? ) 引用符 其他の英数字以外の特殊文字が含まれて居ると 仮令 其等の文字が角括弧で囲まれて居ても コマンドの自動生成ロジックはエラーに成る catalog.schema.table の形式を採るテーブルの完全修飾名はサポートされて居る CommandBuilder に依る SQL ステートメントの自動生成 DataAdapter に対して SQL ステートメントを自動的に生成するには 先ず DataAdapter の SelectCommand プロパティを設定する 次に CommandBuilder オブジェクトを作成し CommandBuilder で SQL ステートメントを自動的に生成する DataAdapter を引数と仕て指定する -21-
Visual Basic ' 変数 connection は 有効な SqlConnection オブジェクトとする Dim adapter As SqlDataAdapter = New SqlDataAdapter( _ "SELECT * FROM dbo.customers", connection) Dim builder As SqlCommandBuilder = New SqlCommandBuilder(adapter) builder.quoteprefix = "[" builder.quotesuffix = "]" Dim custds As DataSet = New DataSet connection.open( ) adapter.fill(custds, "Customers") ' 此処でデータセット内のデータを検証するコードを記述 ' SqlCommandBuilder が無ければ 此の行は失敗する adapter.update(custds, "Customers") connection.close( ) C# // 変数 connection は 有効な SqlConnection オブジェクトとする SqlDataAdapter adapter = new SqlDataAdapter( "SELECT * FROM dbo.customers", connection); SqlCommandBuilder builder = new SqlCommandBuilder(adapter); builder.quoteprefix = "["; builder.quotesuffix = "]"; DataSet custds = new DataSet( ); connection.open( ); adapter.fill(custds, "Customers"); // 此処でデータセット内のデータを検証するコードを記述 // SqlCommandBuilder が無ければ 此の行は失敗する adapter.update(custds, "Customers"); connection.close( ); SelectCommand の変更 INSERT UPDATE DELETE の各コマンドを自動生成した後に SelectCommand の CommandText を変更すると 例外が発生する事が有る 変更された SelectCommand.CommandText に INSERT UPDATE DELETE の各コマンドの自動生成時に使用した SelectCommand.CommandText と矛盾するスキーマ情報が含まれて居る場合 後続の DataAdapter.Update メソッド呼び出しでアクセスする列は SelectCommand に依って参照された現在のテーブルには存在しない可能性が有り 例外が発生する CommandBuilder の RefreshSchema メソッドを呼び出す事で 自動的にコマンドを生成する CommandBuilder が使用するスキーマ情報を更新出来る 何のコマンドが自動的に生成されたかを確認するには CommandBuilder オブジェクトの GetInsertCommand GetUpdateCommand GetDeleteCommand の各メソッドを使用して 自動的に生成されたコマンドへの参照を取得し 関連付けられて居る Command の CommandText プロパティを確認する -22-
自動的に生成された更新コマンドをコンソールに出力するコード例を次に示す Console.WriteLine(builder.GetUpdateCommand( ).CommandText) 次に示す例は 前述の例の続きのコードで有る 此の例では CompanyName 列を ContactName 列に置き換えて Customers テーブルを再作成する RefreshSchema メソッドを呼び出し 新しい列情報を使用して 自動的に生成されたコマンドを更新する Visual Basic ' 変数 connection は 有効な SqlConnection オブジェクトとする connection.open( ) adapter.selectcommand.commandtext = _ "SELECT CustomerID, ContactName FROM dbo.customers" builder.refreshschema( ) custds.tables.remove(custds.tables("customers")) adapter.fill(custds, "Customers") ' 此処でデータセット内のデータを検証するコードを記述 ' SqlCommandBuilder が無ければ 此の行は失敗する adapter.update(custds, "Customers") connection.close( ) C# // 変数 connection は 有効な SqlConnection オブジェクトとする connection.open( ); adapter.selectcommand.commandtext = "SELECT CustomerID, ContactName FROM dbo.customers"; builder.refreshschema( ); custds.tables.remove(custds.tables["customers"]); adapter.fill(custds, "Customers"); // 此処でデータセット内のデータを検証するコードを記述 // SqlCommandBuilder が無ければ 此の行は失敗する adapter.update(custds, "Customers"); connection.close( ); データベースからの単一の値の取得 テーブルやデータストリームの形式ではなく 単に 1 つの値をデータベース情報と仕て返す事が必要な場合が有る 例えば COUNT(*) SUM(Price) AVG(Quantity) 等の集約関数の結果を返す場合で有る Command オブジェクトは ExecuteScalar メソッドを使用して単一の値を返す機能を提供する ExecuteScalar メソッドは 結果セットの 1 行目の 1 列目の値をスカラ値と仕て返す SqlCommand の ExecuteScalar メソッドを使用してテーブル内のレコード数を返すコード例を次に示 -23-
す SELECT ステートメントは Transact-SQL COUNT 集約関数を使用して 指定されたテーブルの行数を表す 1 つの値を返す Visual Basic ' 変数 connection は 有効な SqlConnection オブジェクトとする Dim orderscmd As SqlCommand = New SqlCommand( _ "SELECT COUNT(*) FROM dbo.orders", connection) Dim count As Int32 = CInt(ordersCMD.ExecuteScalar( )) C# // 変数 connection は 有効な SqlConnection オブジェクトとする SqlCommand orderscmd = new SqlCommand( "SELECT Count(*) FROM Orders", connection); Int32 count = (Int32)ordersCMD.ExecuteScalar( ); -24-
データアダプタの作成 此のセクションの内容 ウィザードを使用してデータアダプタを作成する方法 (25 頁 ) データアダプタ構成ウィザードを使用して パラメータを含むデータアダプタの設定に必要な総ての情報を入力する方法を説明する 亦 必要な場合は接続も作成する データアダプタを手動で作成や設定する方法 (26 頁 ) ツールボックスからデータアダプタをドラッグし [ プロパティ ] ウィンドウを使用して設定する方法を説明する ウィザードを使用してデータアダプタを作成する方法 データアダプタ構成ウィザードは データアダプタを作成する為の最も簡単で最も柔軟な方法を提供する 詳細に付いては データアダプタ構成ウィザード を参照され度い 以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在も.NET Framework データプロバイダの主要なコンポーネントだが TableAdapter はデザイナで生成されるコンポーネントで アプリケーションとデータベースの間でデータを移動する処理を簡略化する TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い 使用して居る設定やエディションに依っては 表示されるダイアログボックスやメニューコマンドがヘルプに記載されて居る内容と異なる場合が有る 設定を変更するには [ ツール ] メニューの [ 設定のインポートとエクスポート ] をクリックする 詳細に付いては Visual Studio の設定 を参照され度い 既定では Visual Studio でデータアダプタのデザイン時サポートが無効に成って居る データアダプタの此の様なサポートを有効にするには 此処で示す最初の手順に従って データアダプタをツールボックスに追加する必要が有る データアダプタ データ接続 及び データコマンドをツールボックスに追加するには 1. ツールボックスを右クリックし [ アイテムの選択 ] をクリックする 2.[ ツールボックスアイテムの選択 ] ダイアログボックスの [.NET Framework コンポーネント ] タブで 追加する項目を選択する 例えば.NET Framework SQL Server 用データプロバイダを使用する場合は [SqlDataAdapter] [SqlConnection] 及び [SqlCommand] を選択する 3.[OK] をクリックすると 選択した項目がツールボックスに追加される データアダプタ構成ウィザードを使用してデータアダプタを作成するには 1. 作成して居るフォームやコンポーネントを適切なデザイナで開く 2. ツールボックスの [ データ ] タブから OleDbDataAdapter オブジェクト SqlDataAdapter オブジェクト OdbcDataAdapter オブジェクト 又は OracleDataAdapter オブジェクトをデザインサーフェイスにドラッグする デザイナは フォームやコンポーネントにアダプタのインスタンスを追加し データアダプタ構成ウィザードを起動する -25-
3. ウィザードで次の操作を行う A.2 番目のページで 接続を作成か 選択する 接続の作成の詳細に付いては 接続の確立 を参照され度い セキュリティに関するメモ : 接続文字列の詳細 ( サーバー名 ユーザー名 パスワード等 ) を格納すると アプリケーションのセキュリティに影響を及ぼす事が有る Windows 統合セキュリティを使用すると データベースへのアクセスをより安全に制御出来る 詳細に付いては ADO.NET アプリケーションのセキュリティ保護 を参照され度い B.3 番目のページで アダプタが SQL ステートメントとストアドプロシージャの孰れを使用してデータを読み書きするかを指定する 次の表に示すオプションの孰れかを選択する オプション説明 [SQL ステートメントの使用 ] アダプタがデータセット内にテーブルを作成する時に使用する SQL SELECT ステートメントを定義する 此の SELECT ステートメントに基づいて ウィザードはデータソースを更新する為の UPDATE INSERT DELETE ステートメントも生成する [ 新しいストアドプロシージャの作成 ] SELECT ステートメントを指定すると ウィザードは其のステートメントから データソースの読み取りと更新の為のストアドプロシージャを作成する プロバイダが此のオプションをサポートして居ない場合 此のオプションは淡色表示に成る [ 既存のストアドプロシージャを使用 ] アダプタがデータソースの読み取りと更新に使用する既存のストアドプロシージャを指定する 選択した内容に依って 次のペインに表示される項目が異なる C.4 番目のページでは SELECT ステートメントを作成するか 又は 既存のストアドプロシージャを選択する SQL ステートメントの作成を簡単にする為に [SQL ビルダ ] をクリックしてクエリビルダを起動出来る WHERE 句にパラメータのプレースホルダを含むクエリを作成し 実行時にパラメータの情報を取得出来る 詳細に付いては データアダプタコマンドのパラメータ を参照され度い ウィザードを終了すると 2 ページ目に指定した情報に基づいて接続オブジェクトのインスタンスが作成される 4. アダプタや接続の名前を変更する場合は デザイナでアダプタや接続を個別に選択し [ プロパティ ] ウィンドウで新しい名前を指定する 5. アダプタがデータセットに何の様なデータを格納するかを確認する場合は 結果をプレビュー出来る 詳細に付いては データアダプタの結果をプレビューする方法 を参照され度い アダプタの作成や設定を手動で行う事も出来る 其の場合は 既に接続オブジェクトが使用可能に成って居る必要が有る データアダプタの設定には データソースのテーブルとデータセットのテーブルの間にテーブル割り当てを確立する作業が含まれる 詳細に付いては データアダプタを手動で作成や設定する方法 を参照され度い データアダプタを手動で作成や設定する方法 データアダプタは ウィザードを使用せずに作成出来る アダプタの作成方法に拘らず 常に設定の変更が可能で有る -26-
以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在も.NET Framework データプロバイダの主要なコンポーネントだが TableAdapter はデザイナで生成されるコンポーネントで アプリケーションとデータベースの間でデータを移動する処理を簡略化する TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い 使用して居る設定やエディションに依っては 表示されるダイアログボックスやメニューコマンドがヘルプに記載されて居る内容と異なる場合が有る 設定を変更するには [ ツール ] メニューの [ 設定のインポートとエクスポート ] をクリックする 詳細に付いては Visual Studio の設定 を参照され度い 既定では Visual Studio でデータアダプタのデザイン時サポートが無効に成って居る 此のデータアダプタのサポートを有効にするには 次の最初の手順に従って データアダプタをツールボックスに追加する必要が有る データアダプタ 接続 及び コマンドをツールボックスに追加するには 1. ツールボックスを右クリックし [ アイテムの選択 ] をクリックする 2. 追加する項目を [ ツールボックスアイテムの選択 ] ダイアログボックスの [.NET Framework コンポーネント ] タブで選択する 例えば.NET Framework SQL Server 用データプロバイダを使うには [SqlDataAdapter] [SqlConnection] 及び [SqlCommand] を選択する 3.[OK] をクリックすると 選択した項目がツールボックスに追加される データアダプタを手動で作成するには 1. 使用して居るフォームやコンポーネントへの接続オブジェクトが使用可能で有る事を確認する スタンドアロンの接続を追加する方法に付いては 接続の確立 を参照され度い 2. ツールボックスの [ データ ] タブから OleDbDataAdapter SqlDataAdapter OdbcDataAdapter 又は OracleDataAdapter の各オブジェクトをデザインサーフェイスにドラッグする デザイナは フォームやコンポーネントにアダプタのインスタンスを追加し データアダプタ構成ウィザードを起動する 3. ウィザードを閉じる データアダプタを手動で設定するには 1. アダプタを選択し [ プロパティ ] ウィンドウでデータの読み取りと更新に使用するコマンドを設定する SelectCommand オブジェクトを設定する必要が有る アダプタを使用してデータソースを更新する場合は UpdateCommand DeleteCommand InsertCommand の各オブジェクトも設定する必要が有る 各コマンドオブジェクトに付いて 次のプロパティを設定する プロパティ ActiveConnection 説明接続オブジェクトを参照する為に設定する 接続オブジェクトは [ プロパティ ] ウィンドウの ActiveConnection プロパティで作成出来る 一般に 各コマンドオブジェクトは同じ接続オブジェクトを参照するが アプリケーションでの必要性に応じて 各コマンドに対して異なる接続を使用する事も出来る -27-
CommandText CommandType Parameters SQL ステートメントのテキストやストアドプロシージャの名前で有る プロバイダに依っては CommandText プロパティに複数のステートメントやストアドプロシージャをセミコロン ( ; ) で区切って指定出来る 各ステートメントやプロシージャは 逐次実行される 此れは UPDATE 又は INSERT ステートメントの後に SELECT ステートメントを実行して最新のレコードや自動生成された値 ( 既定値や自動インクリメント値等 ) を取得する場合等に便利で有る CommandText プロパティの値を何の様に解釈するかを示す値で有る コマンドに値を渡す為に設定する Parameter 型のオブジェクトのコレクションで有る SelectCommand オブジェクトでは コマンドにパラメータプレースホルダが含まれる場合丈パラメータコレクションを作成する UpdateCommand InsertCommand 及び DeleteCommand の各オブジェクトには 常にパラメータが必要で有る 詳細に付いては データアダプタのパラメータを設定する方法 を参照され度い 2. データソースとデータセットで同じ列名を使用しない場合は 割り当てを変更する MissingMappingAction プロパティの既定値 (Passthrough) では データソースとデータセットに自動的に同じ名前が生成される 詳細に付いては 方法 : データソース列をデータセットのデータテーブル列に割り当てる を参照され度い 3.[ データ ] メニューの [ データセットの生成 ] をクリックする [ データ ] メニューが表示されない場合は フォームデザイナ 又は コンポーネントデザイナの任意の場所をクリックする 此のメニューはデザイナにフォーカスが有る時に丈表示される 4. データアダプタがデータセットに何の様にデータを格納するかを確認する場合は 結果をプレビューする 詳細に付いては データアダプタの結果をプレビューする方法 を参照され度い データアダプタのパラメータを設定する方法 殆どの場合 データアダプタの Command オブジェクト (SelectCommand InsertCommand UpdateCommand DeleteCommand) は パラメータを必要とする SQL ステートメントやストアドプロシージャを参照する データアダプタ構成ウィザードを使用してアダプタを作成した場合 此等のコマンドに対するパラメータは自動的に設定される 但し 手動でパラメータを設定したり 既存のパラメータコレクションに変更を加えたりする事が必要な場合も有る 以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在も.NET Framework データプロバイダの主要なコンポーネントだが TableAdapter はデザイナで生成されるコンポーネントで アプリケーションとデータベースの間でデータを移動する処理を簡略化する TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い ヒント : コマンドに対する SQL ステートメントに変更を加えた後でパラメータを設定する場合は クエリビルダの [ 此のコマンドのパラメータコレクションを再生成する ] オプションを選択出来る 使用して居る設定やエディションに依っては 表示されるダイアログボックスやメニューコマンドがヘルプに記載されて居る内容と異なる場合が有る 設定を変更するには [ ツール ] メニューの [ 設定のインポートとエクスポート ] をクリックする 詳細に付いては Visual Studio の設定 を参照され度い データアダプタのパラメータを設定するには 1. データアダプタを作成する 詳細に付いては データアダプタの作成 を参照され度い 2. フォームデザイナやコンポーネントデザイナで データアダプタを選択し [ プロパティ ] ウィンドウを開く -28-
3. パラメータを設定するコマンドオブジェクト ( 例えば UpdateCommand) を展開し Parameters プロパティの省略記号 (... ) ボタンをクリックして [Parameter コレクションエディタ ] ウィンドウを開く 4. 新しいパラメータオブジェクトを作成するには [ 追加 ] をクリックする 5. 新しいパラメータを其のパラメータに対するコレクション内の正しいインデックス位置に配置する為に [ 並べ替え ] の下の矢印をクリックしてパラメータを移動する 6. パラメータのプロパティを設定するには [ メンバ ] ボックスのパラメータを選択し 右側に有るプロパティグリッドを使用する 通常設定するプロパティを次の表に示す プロパティ説明 SourceColumn パラメータ値を読み取るデータセットテーブル内の列の名前 此のプロパティは UPDATE INSERT DELETE ステートメント ( 又は 其れに相当するストアドプロシージャ ) に値を格納するパラメータと一緒に使用する SourceVersion パラメータ値が SourceColumn プロパティを通して取得される場合 SourceVersion は パラメータ値のソースと仕て何のバージョンのデータセットレコードを使用するかを指定する Value パラメータに設定する明示的な値 多くの場合 此のプロパティは デザイン時に静的に設定されるのではなく 実行時に設定される Value プロパティと SourceColumn プロパティが共に設定された場合は Value プロパティが優先される NamedParameter パラメータが変数 ( 一般に @parametername と謂う書式を使用 ) やプレースホルダ ( 一般に疑問符を使用 ) に対応するか何うかを示す Boolean 値 SqlConnection オブジェクトと共に名前付きパラメータを使用して居る場合は 此のプロパティを true に設定する DBType Precision パラメータ値のネイティブデータ型 ( データストアでの ) に関する情報 パラメータ値は Scale Size 指定した型に 又は 指定した型から変換される Direction パラメータ値をコマンドに渡すか 又は コマンドから取得するかの指定 ParameterName コレクション内のパラメータをインデックス値で参照する代わりに 参照に使用出来る名前 此のプロパティは 必須では無いが 保守を容易にする為に パラメータ名の使用を推奨する 7.[OK] をクリックして [Parameter コレクションエディタ ] ウィンドウを閉じる 8. 手順 3 ~ 7 を繰り返して 他のコマンドオブジェクトのパラメータを設定する データアダプタの結果をプレビューする方法 データアダプタを設定した後で アダプタがデータセットに何の様にデータを設定するかをテストする事が出来る 以前のバージョンの Visual Studio では アプリケーションとデータベースの通信にデータアダプタが使用されて居た データアダプタは現在も.NET Framework データプロバイダの主要なコンポーネントだが TableAdapter はデザイナで生成されるコンポーネントで アプリケーションとデータベースの間でデータを移動する処理を簡略化する TableAdapter の操作方法の詳細に付いては TableAdapter の概要 を参照され度い -29-
データアダプタの結果をプレビューするには 1. データアダプタを作成する 詳細に付いては データアダプタの作成 を参照され度い 2. コンポーネントトレイでデータアダプタを右クリックし [ データのプレビュー ] をクリックする [ データのプレビュー ] ダイアログボックスが開く 3.[ プレビューするオブジェクトの選択 ] の一覧からデータアダプタを選択する 4. アダプタの SelectCommand プロパティが参照して居るコマンドがパラメータを必要とする場合は [ パラメータ ] グリッドにパラメータ値を入力する 5.[ プレビュー ] をクリックしてデータをプレビューする 6.SelectCommand ステートメントやストアドプロシージャの結果が [ 結果 ] 領域に表示される -30-