Edited at

SqlEntityConnectionTypeProviderについて

More than 3 years have passed since last update.

F# Advent Calendarの11日目です。

この記事は、仕事でSqlEntityConnectionTypeProviderを使用した際に起こった問題のお話です。


SqlEntityConnectionTypeProviderを使うとどんな風に書けるの?


Db.fs

module Db

open System.Data
open System.Data.Entity
open Microsoft.FSharp.Data.TypeProviders

type internal SqlConnection = SqlEntityConnection<ConnectionStringName = "testdb">
let internal context = SqlConnection.GetDataContext()



User.fs

module User =

let internal exists id =
query {
for user in context.Users do
exists(user.Id = id)
}

たったこれだけで書けてしまいます。

スキーマファイルを用意するのも不要です。

(※ connection stringはApp.Configに書き出してます。)

(※ Db.fsを書いた後一度コンパイルする必要があります。)


スキーマファイルも無いのになんでテーブル構造を型として扱えるの?

SqlEntityConnectionTypeProviderはコンパイル時に下記の動作をする為です。


  • connection stringに定義された場所からスキーマを取得する

  • 取得したスキーマから埋め込みリソースとして、ssdl, msl, csdlファイルを保存する

  • スキーマに定義された型を生成する

このほかにも、細かいことをやっているかもしれませんが、大まかにこのぐらいです。

生成されるものを見たい場合はILSpyなどで中身を覗いてみましょう。


EdmxFileを使用しても変わらないんじゃない?

私が考える、Edmxを利用した時より嬉しいことを挙げましょう。


  • コンパイル時に実DBのスキーマを取得する為、テーブル等の変更に対してコンパイル時に気づくことができる場合がある

  • スキーマファイルが埋め込みリソースに格納される為、目に見えなくても良いファイルが見えない

  • 簡易コンテキストと、フルコンテキストが分けられている為、一貫性が保たれる


問題無さそうに思うんですけど?

ここからが本題です。

生成されたスキーマファイルのファイル名、名前空間が下記のように出力されます。

* SqlEntityConnection + 連番

プロジェクトで複数使用していた場合SqlEntityConnection1.*というのが複数作られてしまいます。

コンパイル時にエラーになりそうなものですが、ランタイムエラーとなります。

名前空間を指定できれば回避はできるのですが、指定することができません。

SqlEntityConnectionTypeProviderのコードを見ても、複数プロジェクトを考慮していないような作りになっているように見えます。


まとめ

複数プロジェクトでEFを扱う場合、大人しくEdmxFile型プロバイダーを使用しましょう。

追記

Windows8.1 + VS2013で利用した場合なぜか通りました…。

上記の時はWIn7 + VS2012で起こりました。

時間ができたら調査します。

再追記

上記追記は当時何をやったのかあまり覚えてないですが勘違いでした。

上記で書いた問題の通り、複数プロジェクトで同一のDBに対しては同じ現象が起きます。