かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

F# 2.0でEntity Framework 4.1 CodeFirst その2「関連」

前回の例が単一テーブルだったので複数テーブル間の関連があるケースもやってみました。ちょっとはまったのは、F#って前方参照できないのでEmployee <-> Department間の相互参照させることでした。andで繋げてクラス定義すると前方参照もできるようになるみたいです。つまり1ファイルに必ずまとめて定義しろよってことみたいですね。(間違ってたらコメントください)

ということでさくっとコードだけ載せておきます。

namespace SampleApplication

    open System
    open System.ComponentModel.DataAnnotations
    open System.Data.Entity
    open System.Data.Objects.DataClasses
    open System.Collections.Generic

    // クラスは名前空間に所属させる
    type Department() =
        let mutable id = 0
        let mutable name = ""

        let mutable employees : ICollection<Employee> = null

        member x.ID
            with get() = id
            and set v = id <- v

        member x.Name
            with get() = name
            and set v = name <- v

        abstract Employees : ICollection<Employee> with get, set

        default x.Employees
            with get() = employees
            and set v = employees <- v

    // F#は前方参照したいときはandで繋いで定義するらしい・・・
    and Employee() =

        let mutable id = 0
        let mutable name = ""
        let mutable department : Department = Department()

        member x.ID
            with get() = id
            and set v = id <- v

        member x.Name
            with get() = name
            and set v = name <- v

        abstract Department : Department with get, set

        default x.Department
            with get() = department
            and set v = department <- v

    type EduContext() =
        inherit DbContext()

        // valとDefaultValueを使って未初期化でもOKなように細工
        [<DefaultValue>]
        val mutable employee : IDbSet<Employee>

        [<DefaultValue>]
        val mutable department : IDbSet<Department>

        member public x.Employees
            with get() = x.employee 
            and set v = x.employee <- v

        member public x.Departments
            with get() = x.department
            and set v = x.department <- v

    module Test = 
        [<EntryPoint>]
        let main(_) =
            Database.SetInitializer(
                DropCreateDatabaseIfModelChanges<EduContext>())

            // あとは普通に使える
            use ctx = new EduContext()
            let dept = Department(Name = "人事部")
            ctx.Departments.Add(dept) |> ignore
            // 追加
            ctx.Employees.Add(Employee(Name = "田中 太郎", Department = dept)) |> ignore
            let updateCount = ctx.SaveChanges()
            printfn "%d" updateCount

            // 再読み込み
            ctx.Departments.Load()
            // 取得データの表示
            ctx.Departments
                |> Seq.iter (fun d -> 
                                printfn "%d %s" d.ID d.Name
                                // 部署にぶらさがってる従業員データも表示
                                d.Employees |> Seq.iter (fun e -> printfn "  %d %s" e.ID e.Name))

            0