.NETのO/RマッパーSomaを作り変え中

C#で作っていたのですが、F#が面白いのでF#で作り直すことにしました。Somaは、SQLSQLに埋め込まれた簡易的な式言語をパースしたりするんですが、C#では正規表現をつかって何とかしてました。F#ではこのあたりの処理にF# PowerPackのfsyaccとfslexを使えるんですよね。これが乗り換えた大きな理由だったりします。
で、簡易的な問い合わせは動くようになりました。こんな感じです。

type Department =
{ DepartmentId : int;
DepartmentName : string;
VersionNo : int;
ModifiedDate: DateTime }

type MyDbConfig() =
interface DbConfig with
member
this.Invariant
with get() = "System.Data.SqlClient"
member this.ConnectionStrings
with get() = ConfigurationManager.ConnectionStrings.["Soma.Core.IT"].ConnectionString

[<Test>]
let ``connect to DB with Soma``() =
let config = MyDbConfig()
let departments =
Sql.query<Department> config
<@ let id = 2 in () @>
"select * from Department where DepartmentId = /* id */0"
departments |> List.iter (fun d -> printfn "id = %d, name = %s" d.DepartmentId d.DepartmentName)

上のコードを実行すると、次のような結果が出力されます。最初の行は実行したSQLの簡易的なログ。3行目が上のテストコードでprintfnしているもの。

sql log: select * from Department where DepartmentId = @p0

id = 2, name = Sales

ポイントは、

  • 結果をF#のレコードにマッピング
  • コード引用符でパラメータを渡す
  • SQL中には特別なコメントでパラメータのバインディングや条件分岐を記述できる

といったところです。


条件分岐を使ってSQLを動的に組み立てるには、SQL中に /*% if ... */ と /*% end */ で記述します。

[<Test>]
let ``connect to DB with Soma : using if expression comment``() =
let condtion id = id > 10
let config = MyDbConfig()
let departments =
Sql.query<Department> config
<@ let id = 2 in let condition = condtion id in () @>
"select * from Department where
/*% if condition */
DepartmentId = /* id */0
/*% end */"
departments |> List.iter (fun d -> printfn "id = %d, name = %s" d.DepartmentId d.DepartmentName)

上のコードを実行すると、こういう結果になります。conditionがfalseに評価されるのでwhere句以降は除去され全件取得になります(2件しかないけど)。

sql log: select * from Department

id = 1, name = Account
id = 2, name = Sales

conditionがtrueになるように変えてみると結果はこう変わります。要するにwhere句がちゃんと生成されます。

sql log: select * from Department where 
       
        DepartmentId = @p0

id = 2, name = Sales

今後は、更新系のSQLの自動発行やページングのSQLへの変換処理などもろもろを作っていく予定。今年中に完成できればいいかなぁといった感じです。ちなみに、Entity Frameworkは使わないことにしました。


F#を使ってみて実感しましたが、まちがいなくコード量は短くなりますね。かなりいいです。特にテストが書きやすい。
もちろん、Visual Studioリファクタリングをサポートしてくれればなどの物足りなさはありますが、そこは我慢。次のバージョンではサポートされるよね?

追記 2011/01/17

そういえばソースコードですが下のリポジトリの最近の日付の「Soma.Core」や「Soma.Core.UT」などがF#のプロジェクトです。「Soma」はふるいC#のコード。興味のある方はぜひご覧ください(そして意見あればぜひください)。
http://soma.codeplex.com/SourceControl/list/changesets