2

次のように、データベースからいくつかのレコードとそれらの関係を積極的にロードしたいと思います。

let getEmails() =
    let emails =
        (query { for q in entities.QueueItems do
                    select q.Email
                    take batchSize }
        ).Include(fun (e:Email) -> e.QueueItem)
        |> Seq.toArray

    emails 
    |> Array.iter (fun e -> entities.QueueItems.Remove(e.QueueItem) |> ignore)

    entities.SaveChanges(logger) |> ignore 
    emails

これはうまく機能しますが、クエリ式を括弧で囲んで include を呼び出せるようにする必要がありますが、これは少し奇妙に見えます。より慣用的な F# スタイルで Include を呼び出すヘルパー関数を作成できないかと考えた結果、これにたどり着きました。

module Ef =
    let Include (f:'a -> 'b) (source:IQueryable<'a>) = 
        source.Include(f)

これで、クエリは次のようになります (型推論はクエリ可能な型で機能します:D)

let emails =
    query { for q in entities.QueueItems do
                select q.Email
                take batchSize }
    |> Ef.Include(fun e -> e.QueueItem)
    |> Seq.toArray

コンパイルされます!しかし、実行すると、DbExtensions ライブラリからエラーが表示されます。The Include path expression must refer to a navigation property defined on the type.

Queryable.Include に渡す前にラムダ関数を調べると、次のようになります{<StartupCode$Service>.$Worker.emails@30} Microsoft.FSharp.Core.FSharpFunc<Entities.Email,Entities.QueueItem> {<StartupCode$Service>.$Worker.emails@30}

FSharpFunc問題は、ラムダがどのように解釈されているか、および s とs の間の変換に関係していると思いますExpression<Func<>>。ヘルパー関数を書き直してExpression<Func<'a, 'b>>、最初のパラメーターとして を持たせようとしました。さらに、FSharp.Core ソースをダウンロードして、Seq モジュールと QueryBuilder の実装のインスピレーションを探しましたが、何も機能しませんでした。私はヘルパー関数を次のように再定義しようとしました:

module Ef =
    let Include (y:Expression<Func<'a,'b>>) (source:IQueryable<'a>) = 
        source.Include(y)

しかし、その後、コンパイラ エラーが発生しますThis function takes too many arguments, or is used in a context where a function is not expected

私は少し困惑しています。これを機能させる方法を誰かが提案できますか?

4

1 に答える 1

2

AFAIR 型指定変換は、非カリー化型メンバーにのみ適用され、let バインディングには適用されません。修正として、Ef.Include を静的メンバーに変更してみてください。

type Ef = 
    static member Include (f : Expression<System.Func<'a, 'b>>) = 
        fun (q : IQueryable<'a>)  -> q.Include f
于 2013-05-16T20:30:15.573 に答える