データ アクセス層の接続レベルとコマンド レベルの設定を構成する (C#)
型指定された DataSet 内の TableAdapters により、データベースへの接続、コマンドの発行、DataTable への結果の追加が自動的に行われます。 ただし、これらの詳細を自分で処理する必要がある場合があります。このチュートリアルでは、TableAdapter のデータベース接続レベルとコマンド レベルの設定にアクセスする方法を学習します。
はじめに
チュートリアル シリーズ全体を通して、型指定された DataSet を使用して、階層化アーキテクチャのデータ アクセス層とビジネス オブジェクトを実装しました。 最初のチュートリアルで説明したように、型指定された DataSet の DataTable はデータのリポジトリとして機能しますが、TableAdapters はデータベースと通信して基になるデータを取得および変更するためのラッパーとして機能します。 TableAdapters を使用すると、データベースの操作に伴う複雑さがカプセル化されるため、データベースに接続したり、コマンドを発行したり、DataTable に結果を追加したりするコードを記述する必要がありません。
ただし、TableAdapter の奥深くに潜り込んで、ADO.NET オブジェクトを直接操作するコードを書く必要がある場合もあります。 たとえば、トランザクション内のデータベース変更をラップするのチュートリアルでは、ADO.NET トランザクションを開始、コミット、ロールバックするためのメソッドを TableAdapter に追加しました。 これらのメソッドでは、TableAdapter の SqlCommand
オブジェクトに割り当てられた、手動で作成された内部の SqlTransaction
オブジェクトが使用されました。
このチュートリアルでは、TableAdapter のデータベース接続レベルとコマンド レベルの設定にアクセスする方法について説明します。 特に、基になる接続文字列とコマンド タイムアウト設定にアクセスできるようにする機能を ProductsTableAdapter
に追加します。
ADO.NET を使用したデータの操作
Microsoft .NET Framework には、データを操作するために特別に設計された多数のクラスが含まれています。 System.Data
名前空間内にあるこれらのクラスは、ADO.NET クラスと呼ばれます。 ADO.NET 傘下のクラスの一部は、特定の "データ プロバイダー" に関連付けられています。 データ プロバイダーは、ADO.NET クラスと基になるデータ ストアの間で情報をやり取りするための通信チャネルと考えることができます。 OleDb や ODBC などの汎用プロバイダーと、特定のデータベース システム用に特別に設計されたプロバイダーがあります。 たとえば、OleDb プロバイダーを使用して Microsoft SQL Server データベースに接続することもできますが、SqlClient プロバイダーは、SQL Server 専用に設計および最適化されているため、はるかに効率的です。
プログラムによってデータにアクセスする場合、一般的に次のパターンが使用されます。
- データベースへの接続を確立する。
- コマンドを発行する。
SELECT
クエリの場合は、結果のレコードを操作する。
これらの各手順を実行するための個別の ADO.NET クラスがあります。 たとえば、SqlClient プロバイダーを使用してデータベースに接続するには、SqlConnection
クラスを使用します。 データベースに対して INSERT
、UPDATE
、DELETE
、SELECT
のいずれかのコマンドを発行するには、SqlCommand
クラスを使用します。
トランザクション内のデータベース変更をラップするのチュートリアルを除き、TableAdapter の自動生成コードには、データベースへの接続、コマンドの発行、データの取得、そのデータの DataTables への追加に必要な機能が含まれているため、低レベルの ADO.NET コードを自分で記述する必要はありません。 ただし、これらの低レベルの設定をカスタマイズする必要がある場合もあります。 次のいくつかの手順では、TableAdapter によって内部的に使用される ADO.NET オブジェクトを活用する方法について説明します。
手順 1: Connection プロパティを使用して調べる
各 TableAdapter クラスには、データベース接続情報を指定する Connection
プロパティがあります。 このプロパティのデータ型と ConnectionString
値は、TableAdapter 構成ウィザードで選択した内容によって決まります。 このウィザードで最初に TableAdapter を型指定された DataSet に追加するときに、データベース ソースを尋ねられたことを思い出してください (図 1 を参照)。 この最初の手順のドロップダウン リストには、構成ファイルで指定されたデータベースと、サーバー エクスプローラーのデータ接続内の他のデータベースが含まれます。 使用するデータベースがドロップダウン リストに存在しない場合は、[新しい接続] ボタンをクリックして必要な接続情報を指定して、新しいデータベース接続を指定できます。
図 1: TableAdapter 構成ウィザードの最初の手順 (クリックするとフルサイズの画像が表示されます)
TableAdapter の Connection
プロパティのコードを調べてみましょう。 データ アクセス層を作成するのチュートリアルで説明したように、自動生成された TableAdapter コードを表示するには、[クラス ビュー] ウィンドウに移動し、適切なクラスにドリルダウンして、メンバー名をダブルクリックします。
[表示] メニューに移動し、[クラス ビュー] を選択して (または Ctrl + Shift + C キーを押して) [クラス ビュー] ウィンドウに移動します。 [クラス ビュー] ウィンドウの上半分から NorthwindTableAdapters
名前空間までドリル ダウンし、ProductsTableAdapter
クラスを選びます。 これにより、図 2 に示すように、クラス ビューの下半分に ProductsTableAdapter
のメンバーが表示されます。 Connection
プロパティをダブルクリックすると、そのコードが表示されます。
図 2: クラス ビューで Connection プロパティをダブルクリックして自動生成されたコードを表示する
TableAdapter の Connection
プロパティとその他の接続関連のコードは次のとおりです。
private System.Data.SqlClient.SqlConnection _connection;
private void InitConnection() {
this._connection = new System.Data.SqlClient.SqlConnection();
this._connection.ConnectionString =
ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString;
}
internal System.Data.SqlClient.SqlConnection Connection {
get {
if ((this._connection == null)) {
this.InitConnection();
}
return this._connection;
}
set {
this._connection = value;
if ((this.Adapter.InsertCommand != null)) {
this.Adapter.InsertCommand.Connection = value;
}
if ((this.Adapter.DeleteCommand != null)) {
this.Adapter.DeleteCommand.Connection = value;
}
if ((this.Adapter.UpdateCommand != null)) {
this.Adapter.UpdateCommand.Connection = value;
}
for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
if ((this.CommandCollection[i] != null)) {
((System.Data.SqlClient.SqlCommand)
(this.CommandCollection[i])).Connection = value;
}
}
}
}
TableAdapter クラスがインスタンス化されると、メンバー変数 _connection
は null
と等しくなります。 Connection
プロパティにアクセスすると、最初に _connection
メンバー変数がインスタンス化されているかどうかが確認されます。 されていない場合は、InitConnection
メソッドが呼び出されます。これにより、_connection
がインスタンス化され、その ConnectionString
プロパティが TableAdapter 構成ウィザードの最初の手順で指定された接続文字列値に設定されます。
Connection
プロパティは、SqlConnection
オブジェクトに割り当てることもできます。 これを行うと、新しい SqlConnection
オブジェクトが TableAdapter の各 SqlCommand
オブジェクトに関連付けられます。
手順 2: 接続レベル設定を公開する
接続情報は TableAdapter 内にカプセル化されたままにし、アプリケーション アーキテクチャ内の他のレイヤーからアクセスできないようにする必要があります。 ただし、TableAdapter の接続レベルの情報をクエリ、ユーザー、または ASP.NET ページでアクセスまたはカスタマイズできるようにする必要があるシナリオもあります。
Northwind
DataSet の ProductsTableAdapter
を拡張して、ConnectionString
プロパティを含めましょう。これは、TableAdapter で使用される接続文字列をビジネス ロジック レイヤーが読み取ったり変更したりするために使用できます。
Note
"接続文字列" は、使用するプロバイダー、データベースの場所、認証資格情報、その他のデータベース関連の設定など、データベース接続情報を指定する文字列です。 さまざまなデータ ストアおよびプロバイダーで使用される接続文字列パターンのリストについては、ConnectionStrings.com を参照してください。
データ アクセス層を作成するのチュートリアルで説明したように、型指定された DataSet の自動生成クラスは、部分クラスを使用して拡張できます。 まず、プロジェクトの ~/App_Code/DAL
フォルダーの下に ConnectionAndCommandSettings
という新しいサブフォルダーを作成します。
図 3: ConnectionAndCommandSettings
というサブフォルダーを追加する
ProductsTableAdapter.ConnectionAndCommandSettings.cs
という名前の新しいクラス ファイルを追加し、次のコードを入力します。
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
public partial class ProductsTableAdapter
{
public string ConnectionString
{
get
{
return this.Connection.ConnectionString;
}
set
{
this.Connection.ConnectionString = value;
}
}
}
}
この部分クラスは、ConnectionString
という public
プロパティを ProductsTableAdapter
クラスに追加します。これにより、任意のレイヤーが TableAdapter の基になる接続の接続文字列を読み取ったり更新したりできるようになります。
この部分クラスを作成 (および保存) したら、ProductsBLL
クラスを開きます。 既存のメソッドのいずれかに移動して「Adapter
」と入力し、ピリオド キーを押して IntelliSense を起動します。 IntelliSense で新しい ConnectionString
プロパティが使用可能になっていることがわかります。これは、BLL からこの値をプログラムで読み取ったり調整したりできることを意味します。
接続オブジェクト全体の公開
この部分クラスは、基になる接続オブジェクトの 1 つのプロパティ (ConnectionString
) のみを公開します。 接続オブジェクト全体を TableAdapter の範囲を超えて使用できるようにするには、代わりに Connection
プロパティの保護レベルを変更できます。 手順 1 で調べた自動生成コードでは、TableAdapter の Connection
プロパティが internal
としてマークされていることがわかりました。これは、同じアセンブリ内のクラスからのみアクセスできることを意味します。 ただし、これは TableAdapter の ConnectionModifier
プロパティを使用して変更できます。
Northwind
DataSet を開き、デザイナーで [ProductsTableAdapter
] をクリックして、プロパティ ウィンドウに移動します。 そこで、ConnectionModifier
が既定値の Assembly
に設定されていることがわかります。 Connection
プロパティを型指定された DataSet のアセンブリの外部で使用できるようにするには、ConnectionModifier
プロパティを Public
に変更します。
図 4: Connection
プロパティのアクセシビリティ レベルは、ConnectionModifier
プロパティを使用して構成できます (クリックするとフルサイズの画像が表示されます)
DataSet を保存し、ProductsBLL
クラスに戻ります。 前と同様に、既存のメソッドのいずれかに移動し、「Adapter
」と入力し、ピリオド キーを押して IntelliSense を起動します。 このリストには Connection
プロパティが含まれているため、BLL から任意の接続レベルの設定をプログラムで読み取ったり割り当てたりすることができるようになりました。
手順 3: コマンド関連のプロパティを調べる
TableAdapter は、既定で自動生成された INSERT
、UPDATE
、DELETE
の各ステートメントを持つメイン クエリで構成されます。 このメイン クエリの INSERT
、UPDATE
、DELETE
の各ステートメントは、Adapter
プロパティを介して ADO.NET データ アダプター オブジェクトとして TableAdapter のコードに実装されます。 Connection
プロパティと同様に、Adapter
プロパティのデータ型は、使用するデータ プロバイダーによって決まります。 これらのチュートリアルでは SqlClient プロバイダーを使用するため、Adapter
プロパティは SqlDataAdapter
型です。
TableAdapter の Adapter
プロパティには、INSERT
、UPDATE
、DELETE
の各ステートメントを発行するために使用する SqlCommand
型の次の 3 つのプロパティがあります。
InsertCommand
UpdateCommand
DeleteCommand
SqlCommand
オブジェクトは、データベースに特定のクエリを送信する役割を担い、CommandText
(実行するアドホック SQL ステートメントまたはストアド プロシージャを含む) や Parameters
(SqlParameter
オブジェクトのコレクション) のようなプロパティを持ちます。 データ アクセス層を作成するのチュートリアルで説明したように、これらのコマンド オブジェクトは、プロパティ ウィンドウでカスタマイズできます。
TableAdapter には、メイン クエリに加えて、呼び出されたときに指定されたコマンドをデータベースにディスパッチする可変数のメソッドを含めることができます。 メイン クエリのコマンド オブジェクトと追加のすべてのメソッドのコマンド オブジェクトは、TableAdapter の CommandCollection
プロパティに格納されます。
ここで、ProductsTableAdapter
DataSet の Northwind
によって生成された、これら 2 つのプロパティと、それらをサポートするメンバー変数およびヘルパー メソッドのコードを見てみましょう。
private System.Data.SqlClient.SqlDataAdapter _adapter;
private void InitAdapter() {
this._adapter = new System.Data.SqlClient.SqlDataAdapter();
... Code that creates the InsertCommand, UpdateCommand, ...
... and DeleteCommand instances - omitted for brevity ...
}
private System.Data.SqlClient.SqlDataAdapter Adapter {
get {
if ((this._adapter == null)) {
this.InitAdapter();
}
return this._adapter;
}
}
private System.Data.SqlClient.SqlCommand[] _commandCollection;
private void InitCommandCollection() {
this._commandCollection = new System.Data.SqlClient.SqlCommand[9];
... Code that creates the command objects for the main query and the ...
... ProductsTableAdapter�s other eight methods - omitted for brevity ...
}
protected System.Data.SqlClient.SqlCommand[] CommandCollection {
get {
if ((this._commandCollection == null)) {
this.InitCommandCollection();
}
return this._commandCollection;
}
}
Adapter
および CommandCollection
のプロパティのコードは、Connection
プロパティのコードとよく似ています。 プロパティで使用されるオブジェクトを保持するメンバー変数があります。 プロパティの get
アクセサーは、対応するメンバー変数が null
かどうかをチェックすることから始めます。 その場合は、メンバー変数のインスタンスを作成し、コア コマンド関連のプロパティを割り当てる初期化メソッドが呼び出されます。
手順 4: コマンド レベルの設定を公開する
コマンド レベルの情報は、データ アクセス層内にカプセル化されたままにしておくのが理想的です。 ただし、この情報がアーキテクチャの他のレイヤーで必要な場合は、接続レベルの設定と同様に、部分クラスを介して公開できます。
TableAdapter には 1 つの Connection
プロパティしかないため、接続レベルの設定を公開するためのコードは非常に簡単です。 TableAdapter には複数のコマンド オブジェクト (InsertCommand
、UpdateCommand
、DeleteCommand
) と、CommandCollection
プロパティ内の可変数のコマンド オブジェクトがあるため、コマンド レベルの設定を変更する場合はもう少し複雑になります。 コマンド レベルの設定を更新するときは、これらの設定をすべてのコマンド オブジェクトに反映する必要があります。
たとえば、実行に非常に長い時間がかかった特定のクエリが TableAdapter にあるとします。 TableAdapter を使用してこれらのクエリの 1 つを実行する場合は、コマンド オブジェクトの CommandTimeout
プロパティを増やす必要がある場合があります。 このプロパティは、コマンドの実行を待機する秒数を指定します。既定値は 30 です。
BLL によって CommandTimeout
プロパティを調整できるようにするには、手順 2 で作成した部分クラス ファイル (ProductsTableAdapter.ConnectionAndCommandSettings.cs
) を使用して、次の public
メソッドを ProductsDataTable
に追加します。
public void SetCommandTimeout(int timeout)
{
if (this.Adapter.InsertCommand != null)
this.Adapter.InsertCommand.CommandTimeout = timeout;
if (this.Adapter.DeleteCommand != null)
this.Adapter.DeleteCommand.CommandTimeout = timeout;
if (this.Adapter.UpdateCommand != null)
this.Adapter.UpdateCommand.CommandTimeout = timeout;
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
this.CommandCollection[i].CommandTimeout = timeout;
}
このメソッドは、BLL またはプレゼンテーション レイヤーから呼び出して、その TableAdapter インスタンスによって発行されるすべてのコマンドのコマンド タイムアウトを設定できます。
Note
Adapter
および CommandCollection
のプロパティは private
としてマークされているため、TableAdapter 内のコードからのみアクセスできます。 Connection
プロパティとは異なり、これらのアクセス修飾子は構成できません。 そのため、アーキテクチャ内の他のレイヤーにコマンド レベルのプロパティを公開する必要がある場合は、上記の部分クラスのアプローチを使用して、private
コマンド オブジェクトの読み取りまたは書き込みを行う public
メソッドまたはプロパティを提供する必要があります。
まとめ
型指定された DataSet 内の TableAdapters は、データ アクセスの詳細と複雑さをカプセル化するために機能します。 TableAdapter を使用すると、データベースに接続したり、コマンドを発行したり、DataTable に結果を追加したりするために ADO.NET コードを記述する必要がありません。 すべて自動的に処理されます。
ただし、接続文字列や既定の接続またはコマンドのタイムアウト値を変更するなど、低レベルの ADO.NET の詳細をカスタマイズする必要がある場合があります。 TableAdapter には、自動生成された Connection
、Adapter
、CommandCollection
の各プロパティがありますが、これらは既定では internal
または private
のいずれかです。 この内部情報を公開するには、部分クラスを使用して TableAdapter を拡張し、public
メソッドまたはプロパティを含めます。 または、TableAdapter の Connection
プロパティ アクセス修飾子を、TableAdapter の ConnectionModifier
プロパティを通じて構成できます。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Burnadette Leigh、S ren Jacob Lauritsen、Teresa Murphy、Hilton Geiseno でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。