次のように、データベースからいくつかのレコードとそれらの関係を積極的にロードしたいと思います。
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
。
私は少し困惑しています。これを機能させる方法を誰かが提案できますか?