7.6.3 データコンポーネントの拡張
ここまで、データコンポーネント機能を利用して、ウィザードベースでSQL文の実行メソッドを開発する手法について解説してきた。しかし、実際の業務アプリケーションではすべてのSQL文がウィザードベースで定義できるわけではない。このような場合には、クラスファイルのpartial定義機能(partialクラス)を活用するとよい。これについて解説する。
A. ウィザードベースで定義できないクエリの例
実際の業務アプリケーションでは、ウィザードベースでは定義できないようなクエリも利用されることが多い。例えば以下のようなクエリは、テーブルアダプタ上にウィザードによって追加することができない。
●パラメータ化できないクエリ |
|
・SELECT TOP @top * FROM authors (TOP句はパラメータ化できない)
|
|
●動的に変化するクエリ |
|
・指定された検索条件によってWHERE条件句が変化するようなクエリ
|
B. partialクラスを用いたテーブルアダプタの機能拡張の例
こうしたクエリをテーブルアダプタクラス上に実装したい場合には、クラスファイルのpartial定義機能を利用する※27。この方法について以下に解説する。
※27 partial定義機能の一般論については、「2.3.3 コードビハインド側のクラスのpartial指定に関する注意点」を参照のこと。 |
まず、.xsdファイル上にテーブルアダプタや型付きデータセットを定義した場合、実際には背後でxsd.exeと呼ばれるコード変換ツールが動作し、これによりC#やVBにより記述された実際のテーブルアダプタクラスや型付きデータセットクラスが生成される※28。これらの自動生成されたクラスはすべてpartial定義されているため、ここに簡単にユーザーコードを追加することができる。
※28 Webアプリケーションの場合、自動生成されたこれらのコードを見ることは簡単ではないが、以下のようにすれば見ることができる。(1)Webアプリケーションのデバッグ機能を有効化する。(2)アプリケーションを動作させる。(3)ASP.NETランタイムランタイムにより利用される一時フォルダ(C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\)内に出力されるコードを確認する。これにより、実際にxsd.exeツールなどにより作成されているクラスファイルの定義を確認することができる。テーブルアダプタクラスを拡張する場合には、このコードを参考にするとよいだろう。なお、Visual Studio 2005を利用している場合には、コンソールアプリケーションプロジェクトやクラスライブラリプロジェクトを利用すると、自動生成コードを簡単に確認することができる(これらのプロジェクト種別を利用した場合には、自動生成されたコードが、プロジェクトフォルダ配下に*.Desiner.cs/vbというファイル名で出力されるため、簡単に確認できる)。 |
具体的には図7-34に示すように、App_Codeフォルダ下にクラスファイルを1つ追加し、リスト7-16のようなコード(partialクラス)を記述する。これにより、コンパイルのタイミングで、自動生成されたコードと自らが記述したコードとがマージされ、独自の処理を追加することができるようになる※29 ※30(図7-35)。
※29 リスト7-16のコード中の[DataObjectMethod(DataObjectMethodType.Select)]というメソッド属性は、VisualWeb Developerの各種のウィザードをこのメソッドに認識させるために必要なものである。この属性をつけておくと、ObjectDataSourceコントロールのウィザード画面から当該メソッドを選択することができるようになる。詳細は「第10章 3階層型自動データバインド」を参照のこと。 |
※30 partialクラスを利用して独自のデータアクセスコードを記述する場合には、当然ながらADO.NETクラスライブラリを直接利用してコーディングする必要がある。この際には、安易な文字列連結を避けるなど、本章の前半で解説したようなセキュリティ上の注意点などに留意して実装を行うようにする。 |
|
図7-34 partial定義を行うためのクラスファイルの追加 |
|
図7-35 partial定義によるテーブルアダプタクラスの拡張 |
using System;
using System.Data;
using System.Data.SqlClient;
using System.ComponentModel;
namespace AuthorsDataSetTableAdapters
{
// partial定義による拡張の例
public partial class authorsTableAdapter
{
[DataObjectMethod(DataObjectMethodType.Select)]
public AuthorsDataSet.authorsDataTable GetDataByTop(int n)
{
string query = string.Format("SELECT TOP {0} * FROM authors", n);
SqlDataAdapter sqlda = new SqlDataAdapter(query, this.Connection);
AuthorsDataSet.authorsDataTable table = new AuthorsDataSet.authorsDataTable();
sqlda.Fill(table);
return table;
}
[DataObjectMethod(DataObjectMethodType.Select)]
public AuthorsDataSet.authorsDataTable GetDataByState2(string state)
{
SqlDataAdapter sqlda;
if (state == "all")
{
sqlda = new SqlDataAdapter("SELECT * FROM authors", this.Connection);
}
else
{
sqlda = new SqlDataAdapter("SELECT * FROM authors WHERE state=@state", this.Connection);
sqlda.SelectCommand.Parameters.AddWithValue("@state", state);
}
AuthorsDataSet.authorsDataTable table = new AuthorsDataSet.authorsDataTable();
sqlda.Fill(table);
return table;
}
}
}
|
Imports System.Data
Imports System.Data.SqlClient
Imports System.ComponentModel
Namespace AuthorsDataSetTableAdapters
' partial 定義による拡張の例
Partial Public Class authorsTableAdapter
<DataObjectMethod(DataObjectMethodType.Select)> _
Public Function GetDataByTop(ByVal n As Integer) As AuthorsDataSet.authorsDataTable
Dim query As String = String.Format("SELECT TOP {0} * FROM authors", n)
Dim sqlda As SqlDataAdapter = New SqlDataAdapter(query, Me.Connection)
Dim table As AuthorsDataSet.authorsDataTable = New AuthorsDataSet.authorsDataTable()
sqlda.Fill(table)
Return table
End Function
<DataObjectMethod(DataObjectMethodType.Select)> _
Public Function GetDataByState2(ByVal state As String) As AuthorsDataSet.authorsDataTable
Dim sqlda As SqlDataAdapter
If state = "all" Then
sqlda = New SqlDataAdapter("SELECT * FROM authors",Me.Connection)
Else
sqlda = New SqlDataAdapter("SELECT * FROM authors WHERE state=@state", Me.Connection)
sqlda.SelectCommand.Parameters.AddWithValue("@state", state)
End If
Dim table As AuthorsDataSet.authorsDataTable = New AuthorsDataSet.authorsDataTable()
sqlda.Fill(table)
Return table
End Function
End Class
End Namespace
|
|
リスト7-16 partial定義によるテーブルアダプタクラスの拡張 |
現実問題として、実際の業務アプリではすべてのクエリがウィザードベースで定義できるわけではない。かといって、ウィザードを全く使わない方法では開発生産性が十分に上がらない。このため、ウィザードベースで定義できるクエリについてはテーブルアダプタ構成ウィザードを用いて効率よく開発しつつ、ウィザードベースで定義できないクエリについてはpartialクラスを用いて手作業で実装する。このようにすると、高い開発生産性と高い柔軟性とを両立させることができる。
7.6.4 接続文字列の管理
最後に、接続文字列管理について解説する。ここで解説したデータコンポーネント機能を利用してアプリケーション開発を進めると、実際のデータベースへの接続文字列は、web.configファイル中のconnectionStringsセクションに切り出される(リスト7-17)。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings/>
<connectionStrings>
<add name="pubsConnectionString" connectionString="Data
Source=.\SQLEXPRESS;AttachDbFilename= |DataDirectory|\pubs.mdf;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
...(後略)..
|
|
リスト7-17 テーブルアダプタ構成ウィザードによりweb.configファイルに切り出された接続文字列 |
web.configファイルに切り出された接続文字列に関しては、以下の点に注意していただきたい。
●AttachDbFilename属性 |
|
・データベースファイルアタッチ機能が利用される場合には、接続文字列中に(InitialCatalog属性ではなく)AttachDbFilename属性が指定される。
|
|
・この接続文字列がSQL Server 2005に引き渡されると、データベースは指定されたデータベースファイルを動的にアタッチする。
|
|
・なお、AttachDbFilename属性には|DataDirectory|という特殊文字列を指定することができる。この特殊文字列は、Webアプリケーションの場合、実行時にApp_Dataフォルダの絶対パスに自動的に置換される。
|
|
●User Instance属性 |
|
・この属性により、そのデータベースファイルは当該ユーザーにしか利用できなくなる。そして、利用者がいなくなると自動的にデタッチされるようになる※31。
|
|
●運用系への配置 |
|
・運用環境にアプリケーションを配置する際には、ここに書かれた接続文字列を運用環境に適したものに取り替える。これにより、アプリケーションコードへの修正を加えることなく、環境差異を吸収できる。
|
|
・さらに、ASP.NET 2.0にはweb.configファイルのセクション暗号化機能が追加されている。このため、このconnectionStringsセクションを暗号化してから運用系に配置することができる※32。
|
※31 本機能はSQL Server 2005 Express Editionでしか利用できない機能である。内部動作はやや複雑であるため、詳細が知りたい方は、SQL Server 2005 Express Edition用Books Online(製品ドキュメント)の「管理者以外のユーザーのためのユーザーインスタンス」の項を参照のこと。 |
※32 web.configファイルの暗号化にはaspnet_regiis.exeツールを利用する。詳細な作業手順については製品ドキュメントなどを参照のこと。なお、実際のアプリケーションでは、connectionStringsセクションだけでなく、machineKeyセクションも暗号化する必要がある。 |
さて、ここまでデータコンポーネント機能を活用したデータアクセスについて解説してきたが、実際の業務アプリケーションでこの機能を利用してデータ更新処理を記述する場合には、さらにトランザクション制御コードを記述しなければならないことがある。このような場合には、自動トランザクションを利用すると便利である。
Insider.NET 記事ランキング
本日
月間