次は、Data Access Application BLockを触ってみようと思う。
ざっとドキュメントを見た感じの印象だと、Data Access Application Block(DAAB)を使うと、DBに依存しないアプリケーションが作りやすくなるよっ!
ADO.NETの素のAPIみたいに煩雑なプログラミングしなくてもよくなるよっ!
ってのがいいみたい。
雑にいっちゃうとADO.NETを、いい感じにラップしてくれているもののようです。
ということで、早速お試し。
プロジェクトの作成
DAABSampleという名前でコンソールアプリケーションを作成する。
そこに、必要な参照を追加する。追加するものは以下の5つ。
- Enterprise Library Data Access Application Block
- Enterprise Library Shared Library
- Microsoft.Practices.ObjectBuilder2
- Microsoft.Practices.Unity
- System.Configuration
データベースの作成
データベースにアクセスするプログラムを作るので、DBが無いと始まらない。
ということで、Visual StudioのサーバーエクスプローラからSQL ServerのDBを新規作成した。
DB名は、DAABSampleDBにした。

テーブルは、ありきたりな従業員(Employees)テーブルと部署(Departments)テーブルの2つを作ってEmployeesのDepartmentID列とDepartmentsのID列を外部キーで結んだ。
両テーブルの主キー列は、IDENTITYの設定をして自動で番号がふられるようにしておいた。
このテーブルに対して色々やっていこうと思う。
構成ファイルの編集
DBも準備できたので、続いてEnterprise Libraryではお馴染み構成ファイルを組み立てていこうと思う。
App.configをプロジェクトに追加して、右クリックメニューからEdit Enterprise Library Configurationを選択してApp.configを開く。
Data Access Application Blockが何故か自動的に作られているので、そこにあるLocal Sql Serverを選択してプロパティを編集していく。
Local Sql Serverのノードには、Name, ConnectionString, Provider Nameの3つのプロパティがある。
ここを適時設定していく。今回はNameをDAABSample、ConnectionStringを先ほど作ったDBのものに変更する。
ProviderNameは、SQL ServerなのでそのままでOK。
次に、Data Access Application Blockのノードを選択してDefaultDatabaseをDAABSampleに設定する。
こうすることで、プログラム側で名前を指定しない場合に、自動的にDAABSampleが使われるようになる。
設定は基本的に以上で終了。
やったことをまとめると。
- App.config追加
- Data Access Application BLock/Connection Stringsの下にDBへの接続文字列と名前の設定
- Data Access Application BlockのDefaultDatabaseの設定
やることが少なくてよろしい。
ついにプログラミング
下準備が整ったのでプログラミングに入ろうと思う。
Enterprise Library 4.0から、UnityContainerを中心に物事が進むようになっているので、まずUnityContainerのインスタンスを生成する。
そこに、EnterpriseLibraryCoreExtensionとDataAccessBlockExtensionを追加する。この3つを追加することで、さっき作った構成ファイルをもとにコンテナ内にインスタンスの登録などが行われる。
IUnityContainer container = new UnityContainer();
container.AddNewExtension<EnterpriseLibraryCoreExtension>();
container.AddNewExtension<DataAccessBlockExtension>();
次に、Databaseオブジェクトを取得する。
いつもどおりUnityを使うようにResolveメソッドを使うことでインスタンスの取得が出来る。
// Databaseのインスタンスを取得
var database = container.Resolve<Database>();
// 接続文字列等を出力して正しく取得できているか確認
Console.WriteLine(database.ConnectionString);
正しく設定が出来ていれば、先ほど構成ファイルに記述した接続文字列がコンソールに出力される。
ここにDBアクセスする処理を足していこうと思う。
データの登録処理
まだDBのほうに何もデータが入っていないのでINSERT系の処理を書いていく。
とりあえず、データの登録は一度やっちゃえばいいので、privateメソッドに切り出して書いてみた。
// DBにデータを登録する
private static void DoInsert(Database database)
{
// 部署データを3つ準備
var depts = new[]
{
new { ID = 1, Name = "人事部" },
new { ID = 2, Name = "総務部" },
new { ID = 3, Name = "営業部" }
};
// 部署データ登録用のDbCommand作成
DbCommand insertDept = database.GetSqlStringCommand(
"insert into Departments(ID, Name) values(@ID, @Name)");
// パラメータの登録
database.AddInParameter(insertDept, "ID", DbType.Int64);
database.AddInParameter(insertDept, "Name", DbType.String);
// データの登録
foreach (var dept in depts)
{
database.SetParameterValue(insertDept, "ID", dept.ID);
database.SetParameterValue(insertDept, "Name", dept.Name);
database.ExecuteNonQuery(insertDept);
}
// 登録用の従業員データを4つ準備
var emps = new[]
{
new { ID = 1, Name = "田中 太郎", DepartmentID = 1 },
new { ID = 2, Name = "鈴木 次郎", DepartmentID = 2 },
new { ID = 3, Name = "丸井 三郎", DepartmentID = 3 },
new { ID = 4, Name = "木村 四郎", DepartmentID = 3 }
};
// 従業員データ登録用のDbCommand作成
DbCommand insertEmp = database.GetSqlStringCommand(
"insert into Employees(ID, Name, DepartmentID) values(@ID, @Name, @DepartmentID)");
// パラメータの登録
database.AddInParameter(insertEmp, "ID", DbType.Int64);
database.AddInParameter(insertEmp, "Name", DbType.String);
database.AddInParameter(insertEmp, "DepartmentID", DbType.Int64);
foreach (var emp in emps)
{
database.SetParameterValue(insertEmp, "ID", emp.ID);
database.SetParameterValue(insertEmp, "Name", emp.Name);
database.SetParameterValue(insertEmp, "DepartmentID", emp.DepartmentID);
database.ExecuteNonQuery(insertEmp);
}
}
長いけど、これを実行すると下のようなデータがDBに入る。
Departmentsテーブル
| ID |
Name |
| 1 |
人事部 |
| 2 |
総務部 |
| 3 |
営業部 |
Employeesテーブル
| ID |
Name |
DepartmentID |
| 1 |
田中 太郎 |
1 |
| 2 |
鈴木 次郎 |
2 |
| 3 |
丸井 三郎 |
3 |
| 4 |
木村 四郎 |
3 |
更新系のSQLの発行までの流れは以下の通り。
- database.GetSqlStringCommandメソッドでDbCommandを作成
DbCommand insertDept = database.GetSqlStringCommand(
"insert into Departments(ID, Name) values(@ID, @Name)");
- database.AddInParameterでパラメータの定義
// パラメータの登録
database.AddInParameter(insertDept, "ID", DbType.Int64);
database.AddInParameter(insertDept, "Name", DbType.String);
- database.SetParameterValueでパラメータの値の設定
database.SetParameterValue(insertDept, "ID", dept.ID);
database.SetParameterValue(insertDept, "Name", dept.Name);
- database.ExecuteNonQueryでSQL文の実行
database.ExecuteNonQuery(insertDept);
この一連の処理をTransactionScopeで括ってやると、トランザクションもばっちりになる。
しかも、TransactionScopeを使ってると、コネクションを自動でキャッシュしてくれるらしいので、ローカルなトランザクションで済むという素敵なつくりになっているみたいです。
データの検索処理
データの準備が出来たので、検索系の処理のときの例も作ってみる。
// DbCommandを作成してパラメータの設定を行う
DbCommand cmd = database.GetSqlStringCommand(
"select d.ID, d.Name from Departments d where ID = @ID");
database.AddInParameter(cmd, "ID", DbType.Int64);
database.SetParameterValue(cmd, "ID", 1);
// DataSetを作成して、そこにSQLの結果を読み込む
DataSet ds = new DataSet();
database.LoadDataSet(cmd, ds, "Departments");
// 試しにデータを出力してみる
DataTable deptTable = ds.Tables["Departments"];
Console.WriteLine(deptTable.TableName);
DataRow deptRow = deptTable.Rows[0];
Console.WriteLine("Dept: ID = {0}, Name = {1}", deptRow["ID"], deptRow["Name"]); // -> Dept: ID = 1, Name = 人事部
これも、基本的にDbCommandを作ってパラメータの定義と値を設定する。
そして、Databaseクラスに定義されている、各種読み込みメソッドを使ってデータを読み込む。
今回は、LoadDataSetを使ってDataSetに直接SQLの実行結果を取り込んでいる。
IDataReaderを使う場合はExecuteReaderメソッドを使う。
using(IDataReader r = database.ExecuteReader(cmd))
{
while (r.Read())
{
long id = r.GetInt64(0);
string name = r.GetString(1);
Console.WriteLine("Dept: ID = {0}, Name = {1}", id, name);
}
}
ExecuteReaderの結果のIDataReaderは、きちんとCloseしないといけない。とりあえず、usingで括っておけばOK。
試してみた感想
試してみていいな~と思った部分を列挙してみる。
- コネクションを意識しなくてもいい
- ADO.NETで直接やるよりコードが少なくなる
- TransactionScopeとの相性もよさそうらしい
次に、どうなんだろ?と思った点は
- 型付きデータセットとの相性は、そこまでよくないかも?
型付きデータセットを普通に作るとTableAdapterまで作られちゃうからそっち使っちゃいそう。
- DataSetではない、普通のClassへデータを詰め替えるのがメンドクサイかも?
IDataReaderを使って地道にぐるぐる回すしかなさそう。(ユーテリティクラス作ればいいか)
全体的には、シンプルになっていいな~と思った。