Somaの式コメントでオリジナルの関数を使う
このエントリは、Soma 1.2.0.0を利用する際のTipsです。
はじめに
Somaでは、SQLを動的に組み立てるためにSQLコメント(式コメント)内で利用できる関数があらかじめ組み込まれていて、たとえば次のように使えます。
select * from Employee where /*%if not (isNullOrEmpty employeeName) */ EmployeeName = /* employeeName */'smith' /*%end */
この例では isNullOrEmpty があらかじめ組み込まれた関数で、引数がnullだったり空文字だった場合にtrueを返します。
以降では、isNullOrEmpty のような関数をアプリケーションで定義し利用する方法を紹介します。
パラメータで渡す方法
一番簡単なのは、パラメータで渡す方法です。次の例では、問い合わせ条件がnullだったりオプション型のNoneだったりした場合に"UNKNOWN"という文字列に置換するadjustという関数を作成してquery関数のパラメータに渡しています。
open Systemこの例を動かすと次のSQLがログ出力されます。
open Soma.Coretype Condition =
{ Name : string option
Salary : decimal option }[<EntryPoint>]
let main args =let adjust (obj:obj) =
let unknown = "UNKNOWN"
match obj with
| :? option<string> as x ->
if x.IsSome then x.Value else unknown
| x ->
if x <> null then x.ToString() else unknownlet config =
{ new MsSqlConfig() with
member this.ConnectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=True" }let employee =
Db.query<dynamic>
config
"select * from Employee where EmployeeName = /* adjust c.Name */'test' and Salary > /* c.Salary */0"
["c" @= { Name = None; Salary = Some 1000M }; "adjust" @= adjust]printfn "%A" employee
Console.ReadKey() |> ignore
0
LOG : select * from Employee where EmployeeName = N'UNKNOWN' and Salary > 1000
Dialectに登録する方法
上の方法は簡単ですが、毎回パラメータで渡すのは面倒です。
といわけで次に説明するのは、一度登録しておけば使える方法です。次の例では、MsSqlDialectをオブジェクト式で生成する際にadjust関数を登録しています。利用するときは登録した名前で参照して使います。先ほどの例と違ってquery関数のパラメータでは渡していないことに注目してください。
open System
open System.Collections.Generic
open Soma.Coretype Condition =
{ Name : string option
Salary : decimal option }[<EntryPoint>]
let main args =let adjust (obj:obj) =
let unknown = "UNKNOWN"
match obj with
| :? option<string> as x ->
if x.IsSome then x.Value else unknown
| x ->
if x <> null then x.ToString() else unknownlet dialect =
{ new MsSqlDialect() with
member this.RootExprCtxt =
let exprCtxt = new Dictionary<string, obj * Type>(base.RootExprCtxt) :> IDictionary<string, obj * Type>
exprCtxt.["adjust"] <- (box adjust, adjust.GetType())
exprCtxt } :> IDialectlet config =
{ new MsSqlConfig() with
member this.ConnectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=True"
member this.Dialect = dialect }
let employee =
Db.query<dynamic>
config
"select * from Employee where EmployeeName = /* adjust c.Name */'test' and Salary > /* c.Salary */0"
["c" @= { Name = None; Salary = Some 1000M }]printfn "%A" employee
Console.ReadKey() |> ignore
0
この例を動かすと先ほどの例と同じく次のSQLがログ出力されます。
LOG : select * from Employee where EmployeeName = N'UNKNOWN' and Salary > 1000
既存の組み込み関数に別名をつける
Dialectに登録する方法を使うと、既存の組み込み関数に別名をつけたりすることも簡単です。たとえば、先ほどの例のMsSqlDialectのオブジェクト式のところを次のように変更し、「isNullOrEmpty」の別名として「hoge」を登録します。
let dialect =この設定をすれば、一番最初の組み込み関数を利用したSQLの例は次のように書けることになります。つまり、「isNullOrEmpty」の代わりに「hoge」と書けます。
{ new MsSqlDialect() with
member this.RootExprCtxt =
let origCtxt = base.RootExprCtxt
let exprCtxt = new Dictionary<string, obj * Type>(origCtxt) :> IDictionary<string, obj * Type>
exprCtxt.["adjust"] <- (box adjust, adjust.GetType())
exprCtxt.["hoge"] <- origCtxt.["isNullOrEmpty"]
exprCtxt } :> IDialect
select * from Employee where /*%if not (hoge employeeName) */ EmployeeName = /* employeeName */'smith' /*%end */