バッチ系の処理
バッチ系の処理の場合、SELECTで条件に合致したレコードすべてに対して何らかの処理を行う。という形になると思います。この場合は生ADO.net(DbConnection/DbCommand/DbDataReader)が相性が良いと思います。
こいつは古き良きスタイルなので、レコードを一行一行読んで処理して、という形に自然になること。また、DBへの接続と切断をコントロールしやすいのもメリットです。対象のRDBMSに応じて、DbXxx抽象クラスの派生クラスを使うことで、それぞれのRDBMSの特性を生かした実装ができるのもいいですね。
(型あり|型無し)データセットだと、一旦まとめて読みこむ形になるので、バッチ系処理ではかえって制御が難しいように思います。
EF(Entity Framework)もバッチ処理で使いにくいわけではなさそうですが、たとえばSQLServerなんかだとロックエスカレーションによるデッドロックを回避するために、SELECT時にロックヒントを付けたりしますが、こんな感じのRDBMSごとの配慮がいちいち面倒なイメージがあります。実際にバッチ系処理で使ったことはないですが。
Webアプリケーション
Webアプリの場合はプレゼンテーション側のアーキテクチャを何にするかによると思います。僕の場合は好みの問題で、全力でASP.net MVCを推します。この場合はEFを選択するのがたぶん楽です。
どうしてもASP.net (Webフォーム)から逃げられなかった場合は、型無しデータセットかな。
その他 (2層C/S、3層C/S、Webサービス、etc...)
そのほかはケースバイケースになりますが、メリットデメリットを加味しながら、基本的には好みでEFか、型無しデータセットか、生ADO.netのいずれかを選ぶかな。この3つ以外は選択肢から除外。
ただし…
EFを使う場合は、モデルファーストかコードファーストで開発を始めるのがよいと思います。コードファーストはいろいろ批判的な意見も見かけますが、僕は結構好きです。
それと、インデクッスやトリガ、ストアドプロシージャなんかはどう使うか、何処で使うか、どのタイミングで実際に適用するか。ここら辺は十分な配慮が必要でしょう。あと、ビューは使いづらいです。多分。
型無しデータセットを使う場合は、コードのメンテナンシビリティを保つために、以下の2つを守ることがおススメです。
- foeach構文でDataTable.Rowsプロパティを使わない。代わりにDataTable.AsEnumerable拡張メソッドを使う。
- DataRowクラスのインデクサを使わない。代わりにDataRow.Field拡張メソッドとDataRow.SetField拡張メソッドを使う。
- DataTableの各レコードに対して、Enumerable拡張メソッドが使いやすくなり、コードが比較的きれいになる。
- フィールドからのデータ取得時のキャストが不要になる。また、Nullableを使ってDBNullをNULLにマップできる。
と、形無しデータセットでも、少しはイマドキなコードが書けるようになります。例をあげてみましょう。たとえば、取得済みのDataTable「t」から、「Kana」順に「Name」と「Birthday」を取得してイロイロ。しかも「Birthday」はNullable。ならこんなコードになります。
DataTable t = GetTable(); foreach (var row in t.AsEnumerable().OrderBy(r => r.Field<string>("Kana"))) { var name = row.Field<string>("Name"); var birthday = row.Field<DateTime?>("Birthday"); // name,birthdayを使っていろいろ処理 }このコードは、当然Selectメソッドで匿名クラスを作ったりしても問題なく行けます。個人的は「これなら使ってもいっか。」という気になります。
そして、生ADO.netを使う場合は、多段usingネストを減らす工夫があるとよいでしょう。
とりあえずそこは、ちょっと長くなったので別エントリで書くことにします。