F#でSomaを使うメリット

かんたんにいうとF#の次の特長を活かせます。

  • nullを排除できる
  • 値をimmutableにできる

それってF#なんだから当然でしょ、と思うかもしれません。しかし、既存のO/Rマッパーを使おうとすると上の2つの特徴はたやすく犠牲になってしまうのです。既存のO/Rマッパーの例としては、LINQ to SQL とか Entity Frameworkとかを挙げられます。


nullの扱いについてF#でLINQ to SQLを使う例で考えてみましょう。LINQ to SQLのデザイナやクラス生成機能はF#のプロジェクトでは作れません。これはC#のプロジェクトで作ります。次のように使用できます。この例では従業員テーブルから主キーで一件取得して名前の長さをみて何かするという処理です。従業員の名前はDB上でNULLの場合がありうるとします。

use db = new ExampleDataContext()
let employee =
query <@ seq { for e in db.Employee do if e.EmployeeId = 1 then yield e } @>
|> Seq.head
if employee.EmployeeName <> null then // このチェックをわすれると実行時にNullReferenceException
let length = employee.EmployeeName.Length

LINQ to SQLのデザイナで生成されたクラスではEmployeeNameはString型です。つまりnullが入り得ますのでチェックし忘れるとふつうにNullReferenceExceptionが発生します。


一方、Somaで同じことをしてみます。クラスはデザイナから生成できませんがnullになり得るところはオプション型にしておくことができます。EmployeeNameがStringのオプション型です。

  let employee = ExampleDb.find<Employee> [1]
let length = employee.EmployeeName.Length // オプション型だとコンパイルエラーになってコンパイル時に気づける

オプション型にはLengthプロパティはないのでコンパイルエラーになります。そのためまちがいに気づけますし直して安全なコードにできます。


値をimmutableにできるかどうかはO/Rマッパーが対応していないとなんともならないです。LINQ to SQL とか Entity Frameworkが対応できているかどうかちゃんと確認していませんが、少なくともデザイナが生成するコードはmutableです。
Somaではレコード型に対応しているので完全にimmutableにできます(レコード型のフィールドをmutableにすることも可能ですがそうしないという前提)。insertやupdateで主キーやバージョン番号を内部的に変更する場合であっても新しいレコードのインスタンスを作って返すようにしています。
というわけで、F#の特長を活かしてDBアクセスするならSomaがおすすめという話でした。