F# で Entity Framework Coreる

この記事はF# Advent Calendar 2017の5日目の記事です。 遅刻しましたごめんなさい…。

F# + .NET Core + Entity Frameworkの組み合わせて開発してみたときの備忘です。 もしかしたら多少古い知識が混ざっているかもれません(全部再検証するには時間がたりなかった)。

モデル定義

CLIMutableにしてEntityFramework側で処理できるようにしておきます。  また、マイグレーション機能を使うためにいくつかAttributeをつけて起きます。

open System
open System.ComponentModel.DataAnnotations
open System.ComponentModel.DataAnnotations.Schema

type UserId = int64

[<CLIMutable>]
type User = {
  [<Key; DatabaseGenerated(DatabaseGeneratedOption.Identity)>]
  Id: UserId
  [<Required; StringLength(32)>]
  Name: string
}

DBContext

だいたいC#のサンプルを翻訳していくだけです。

open Microsoft.EntityFrameworkCore
open Microsoft.Extensions.PlatformAbstractions

type HogeDbContext() =
  inherit DbContext()

  [<DefaultValue>]
  val mutable user : DbSet<User>

  static member val ConnectionString = "" with get, set

  member this.Users
    with get() = this.user
    and set v = this.user <- v

  override __.OnConfiguring(optionsBuilder: DbContextOptionsBuilder) =
    optionsBuilder.UseMySql(SpellbookLibraryDbContext.ConnectionString)
|> ignore

ここではMySQLでの例をだしましたが、他のDBでも大した違いはないはずです。

マイグレーションコード

C#であれば Microsoft.EntityFrameworkCore.Tools.DotNet をインストールしてコマンドを叩いてあげれば C#マイグレーションコードが生成されます。

ではF#であればF#のコードをだして…くれません。

https://github.com/aspnet/EntityFrameworkCore/pull/10289

このpull requestと関連issueを読めばわかりますが、C#以外の言語はコミュニティに任せたそうな雰囲気を感じます。 とはいえ、このpull requestを含む2.1.0はまだリリースされていませんし、コミュニティでツールが作成されるのもそれなりに時間がかかるでしょう。

では、マイグレーションを諦めるのか…といえば、いやいや、方法はあります。

  1. マイグレーション部分だけC#でやる
  2. 生成されたC#コードをすべてF#に書き直す

後者に関しては、F#で書いたモデルクラスからもマイグレーションコードを生成できるので、マイグレーションコードさえなんとかしてしまえば良いわけです。

ただし、2テーブルの作成に200行ほどのF#を書かないといけないので労力に見合っていないのがネックです。

気合で書くか、待つか、ツールを実装するか。 お好みのものをお選び下さい。