带谓词的查询函数

ebb*_*ebb 1 f#

Mjello在那里!我正在尝试创建一个F#应用程序,现在我已经打了另一面墙.

问题出现在Microsoft.FSharp.Linq.Query模块中,query如果它们作为参数传递,那里的函数就不会接受我的谓词.看一下这个:

member x.GetUsersWhere (e:User -> bool) =
    query <@ ctx.Users |> Seq.filter e @>
Run Code Online (Sandbox Code Playgroud)

然后我称之为:

let service = new UserService()
service.GetUsersWhere (fun z -> z.Name = "James")
Run Code Online (Sandbox Code Playgroud)

那应该没问题呃?好吧,编译器同意:

在查询中使用了以下构造,但F#-to-LINQ查询转换器无法识别:Call(None,System.Collections.Generic.IEnumerable 1[WebFSharp.Entities.User] op_PipeRight[DbSet1,IEnumerable 1](System.Data.Entity.DbSet1 [WebFSharp.Entities.User],Microsoft.FSharp.Core. FSharpFunc 2[System.Data.Entity.DbSet1 [WebFSharp.Entities.User],System.Collections.Generic.IEnumerable 1[WebFSharp.Entities.User]]), [PropertyGet (Some (FieldGet (Some (Value (WebFSharp.Business.UserService)), WebFSharp.Business.MyContext ctx)), System.Data.Entity.DbSet1 [WebFSharp.Entities.User] Users,[]),Let(predicate,Value(),Lambda(source,Call(None,System.Collections) .Generic.IEnumerable 1[WebFSharp.Entities.User] Filter[User](Microsoft.FSharp.Core.FSharpFunc2 [WebFSharp.Entities.User,System.Boolean],System.Collections.Generic.IEnumerable 1[WebFSharp.Entities.User]), [predicate, Coerce (source, System.Collections.Generic.IEnumerable1 [[WebFSharp.Entities.User,WebFSharp.Entities,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null ]])])))])这不是一个有效的查询表达式.检查允许查询的规范,并考虑将部分查询移出报价

这是怎么回事?是因为在Expr将参数注入到它之前会对它进行评估吗?

无论如何,以下代码有效,但灵活性要低得多:

member x.GetUsersByName name =
    query <@ ctx.Users |> Seq.filter(fun z -> z.Name = name) @>

let service = new UserService()
service.GetUsersByName "James"
Run Code Online (Sandbox Code Playgroud)

有谁可以请谈谈发生了什么?

Tom*_*cek 8

在您的代码中,F#到LINQ转换器没有任何方法来检查您指定的函数(参数e是一些已编译的代码 - 没有办法获得可以转换为SQL的引用表示).

你需要使用Expr<User -> bool>而不是User -> bool.这意味着您不会传递函数,而是传递一些用作参数的代码(可以分析并转换为SQL):

member x.GetUsersWhere (e:Expr<User -> bool>) = 
    query <@ ctx.Users |> Seq.filter %e @>
Run Code Online (Sandbox Code Playgroud)

注意%e语法 - 这意味着引用的代码应该嵌入(拼接)到主引用表达式中,因此翻译者将其视为单个表达式.调用它时,您还需要使用引号传递函数:

let service = new UserService()service.GetUsersWhere <@ fun z -> z.Name = "James" @>
Run Code Online (Sandbox Code Playgroud)