2

我想急切地加载从数据库中像这样的一些记录和他们的关系:LINQ的包括F#风格流水线辅助函数

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 

这个伟大的工程,但我必须包装在括号中的查询表达式能够打电话给它看起来有点奇怪。我想知道是否可以编写一个辅助函数来以更惯用的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.

检查lambda函数在传递给Queryable.Include之前,它看起来像这样{<StartupCode$Service>[email protected]} Microsoft.FSharp.Core.FSharpFunc<Entities.Email,Entities.QueueItem> {<StartupCode$Service>[email protected]}

我想问题是如何解释我的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

我有点难住。任何人都可以建议我如何才能得到这个工作?

回答

1

AFAIR类型定向转换仅适用于uncurried类型成员,不允许绑定。 作为一个修复,你可以尝试改变Ef.Include是一个静态成员

type Ef = 
    static member Include (f : Expression<System.Func<'a, 'b>>) = 
     fun (q : IQueryable<'a>) -> q.Include f 
+0

伟大的解决方案!花时间去阅读类型转换。非常感谢。 –