我想急切地从数据库中加载一些记录及其关系,如下所示:
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,这看起来有点奇怪。我想知道我是否可以编写一个辅助函数来调用Include以更加惯用的F#风格,我想出了这个。
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.
在将lambda函数传递给Queryable.Include之前检查它,它看起来像{<StartupCode$Service>.$Worker.emails@30} Microsoft.FSharp.Core.FSharpFunc<Entities.Email,Entities.QueueItem> {<StartupCode$Service>.$Worker.emails@30}
。
我想问题与我的lambda如何被解释以及FSharpFunc
和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
。
我有点难过。任何人都可以建议我如何使这个工作?
答案 0 :(得分:1)
AFAIR类型定向转换仅适用于未经处理的类型成员,不允许绑定。 作为修复,您可以尝试将Ef.Include更改为静态成员
type Ef =
static member Include (f : Expression<System.Func<'a, 'b>>) =
fun (q : IQueryable<'a>) -> q.Include f