Linq包含f#样式流水线的辅助函数

时间:2013-05-16 18:56:35

标签: entity-framework f# ef-code-first pipelining query-expressions

我想急切地从数据库中加载一些记录及其关系,如下所示:

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如何被解释以及FSharpFuncExpression<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

我有点难过。任何人都可以建议我如何使这个工作?

1 个答案:

答案 0 :(得分:1)

AFAIR类型定向转换仅适用于未经处理的类型成员,不允许绑定。 作为修复,您可以尝试将Ef.Include更改为静态成员

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