2

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

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

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

4

1 回答 1

2

AFAIR 类型导向的转换仅适用于非柯里化类型成员,而不适用于 let 绑定。作为修复,您可以尝试将 Ef.Include 更改为静态成员

type Ef = 
    static member Include (f : Expression<System.Func<'a, 'b>>) = 
        fun (q : IQueryable<'a>)  -> q.Include f
于 2013-05-16T20:30:15.573 回答