Soma 0.1.0.1 のクエリ機能の紹介

Somaは「Sql Oriented MApping framework」のアクロニムです。というわけでSQLを柔軟に発行できるのがアピールポイントです。今日はSomaの中心機能であるクエリ機能を紹介したいと思います。

SQLS2Daoに由来する2 Way SQLSQL文字列をそのままツールで実行して構文チェックでき、かつ、実行時には適切に書き換えてパラメータにバインディングしたり動的にSQLを組み立てられる、という2とおりの使いができるSQL)で記述できます。そして、結果セットはレコード型やタプル型にマッピングできます。たとえば、従業員の名前で検索する例はこうなります(ジェネリクパラメータのEmployeeはレコード型です)。

let empList = 
Db.query<Employee>
dbConfig
"select * from Employee where EmployeeName = /* name */'test'"
<@ let name = "Smith" in () @>
ここで注目してほしいのは、コード引用符でパラメータを渡していることです。コード引用符内のletで束縛したものが2 Way SQL中のコメント式で参照できるようになります。上の例ではlet name = "Smith"で束縛した値をSQL中のコメント/* name */でSQLのバインド変数に関連づけています。


コード引用符内に定義した関数をSQLのコメント式から呼び出すこともできます。次の例では、コード引用符内に定義したsubstring関数を呼び出しています。

let empList = 
Db.query<Employee>
dbConfig
"select * from Employee where EmployeeName = /* substring name 1 */'test'"
<@ let name = "xSmith" in let substring (s:string) i = s.Substring(i) in () @>
SQLのコメント式では、パラメータのバインディングや関数呼び出しのほかに四則演算や論理演算ができます。


コメント式では条件分岐やループを表現でき、SQLを動的に組み立てられます。次の例では、nameがnullの場合、WHERE句が自動で除去されます。

let empList = 
Db.query<Employee>
dbConfig
"select * from Employee where /*% if name <> null */ EmployeeName = /* name */'test' /*% end */"
<@ let name:string = null in () @>


これまでの例では、Employeeというレコード型に結果セットをマップしていました。ジェネリックパラメータで示すことでタプル型にマッピングすることもできます。次の例では、EmployeeIdとEmployeeNameをintとstringのタプルにマッピングしています。

let empList = 
Db.query<int * string>
dbConfig
"select EmployeeId, EmployeeName from Employee"
<@ () @>


タプルの要素にはレコードの要素も入れられます。次の例では、DepartmentIdとEmployeeテーブルの値をintとEmployeeのタプル型にマッピングします。

let empList = 
Db.query<int * Employee>
dbConfig
"select DepartmentId, Employee.* from Employee"
<@ () @>
タプル型にマッピングできるのは、非常に便利な機能だと思っています。なんでもかんでもタプルで処理するのは考えものですが、作成しなければいけないレコード型の量を抑えることができるはずです(結果セットごとにDTOに相当する型をつくらなくていい!)。


これまでの例は、どれもF#のリストを返します。つまり、関数の呼び出しが返ってきた時点で結果セット全件を読み出してしまっています。しかし、次の例のようにF#のシーケンスで取得することもできます。この例では、Employeeテーブルの全件を取得するSQLを発行するものですが、関数の呼び出しが返ってきた時点ではSQLはまだ発行されていません。シーケンスを実際に処理する時点で初めてSQLが発行され、内部的にDbDataReaderを読み出しながら1件ずつ処理されます。

let empSeq = 
Db.queryOnDemand<Employee>
dbConfig
"select * from Employee"
<@ () @>
通常はリストで処理して、ここぞというところでシーケンスを使うのがいいのかなぁとは思いますが、アプリの特性に応じて使ってもらえればと思います。


以上、Somaのクエリ機能の紹介でした。
ほかにも便利機能はいろいろありますが、ここで紹介したクエリ機能とhttp://soma.codeplex.com/に示したレコード一件を扱うCRUD処理のAPIがあればDBアクセスに必要な大方のことはできるんじゃないかと思います。