我想从数据库中急切地加载一些记录及其关系,如下所示:
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 之前检查 lambda 函数,它看起来像这样{<StartupCode$Service>.$Worker.emails@30} Microsoft.FSharp.Core.FSharpFunc<Entities.Email,Entities.QueueItem> {<StartupCode$Service>.$Worker.emails@30}
。
我想问题与我的 lambda 如何被解释以及FSharpFunc
s 和Expression<Func<>>
s 之间的转换有关。我尝试重写我的辅助函数,使其具有一个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
。
我有点难过。任何人都可以建议我如何让这个工作?