我一直在这里查询查询表达式 msdn .microsoft/en-us/library/vstudio/hh225374.aspx
I've been looking at query expressions here msdn.microsoft/en-us/library/vstudio/hh225374.aspx
我一直想知道为什么以下内容是合法的
And I've been wondering why the following is legitimate
let testQuery = query { for number in netflix.Titles do where (number.Name.Contains("Test")) }但是你真的不能做这样的事情
But you can't really do something like this
let christmasPredicate = fun (x:Catalog.ServiceTypes.Title) -> x.Name.Contains("Christmas") let testQuery = query { for number in netflix.Titles do where christmasPredicate }当然F#允许这样的可组合性,所以您可以重用谓词??如果我想将圣诞节标题与另一个谓词(例如在特定日期之前)结合起来怎么办?我必须复制并粘贴整个查询吗? C#与此完全不同,它具有几种构建和组合谓词的方法
Surely F# allows composability like this so you can reuse a predicate?? What if I wanted Christmas titles combined with another predicate like before a specific date? I have to copy and paste my entire query? C# is completely unlike this and has several ways to build and combine predicates
推荐答案对于需要显式引号的F#2.0版本的查询,这很容易做到(我写了有关它的博客文章).有一种方法可以在C#中实现类似的目的(另一个博客文章),我认为类似的技巧可能是在F#3.0中玩过.
This was quite easy to do with the F# 2.0 version of queries which required explicit quotations (I wrote a blog post about it). There is a way to achieve similar thing in C# (another blog post) and I think similar tricks could be played with F# 3.0.
如果您不介意较丑陋的语法,则也可以在F#3.0中使用显式引号.当你写 query { .. }编译器实际上生成如下内容:
If you do not mind uglier syntax, then you can use explicit quotations in F# 3.0 too. When you write query { .. } the compiler actually generates something like:
query.Run(<@ ... @>)其中<@ .. @>中的代码用F#代码引用-即,以Expr类型存储的代码代表源代码,并且可以转换为LINQ表达式,从而转换为SQL.
where the code inside <@ .. @> is quoted F# code - that is, code stored in an Expr type that represents the source code and can be translated to LINQ expressions and thus to SQL.
这是我使用SqlDataConnection类型提供程序进行测试的示例:
Here is an example that I tested with the SqlDataConnection type provider:
let db = Nwind.GetDataContext() let predicate = <@ fun (p:Nwind.ServiceTypes.Products) -> p.UnitPrice.Value > 50.0M @> let test () = <@ query.Select ( query.Where(query.Source(db.Products), %predicate), fun p -> p.ProductName) @> |> query.Run |> Seq.iter (printfn "%s")关键技巧是,当您使用显式报价(使用<@ .. @>)时,可以使用%运算符进行报价切片.这意味着predicate的引号将放在您写%predicate的地方的查询的引号中(在test中).
The key trick is that, when you use explicit quotations (using <@ .. @>) you can use the % operator for quotation slicing. This means that the quotation of predicate is put into the quotation of the query (in test) in place where you write %predicate.
与漂亮的查询表达式相比,代码很丑陋,但是我怀疑您可以通过在此之上编写一些DSL或对报价进行预处理来使它更好.
The code is quite ugly compared to the nice query expression, but I suspect you could make it nicer by writing some DSL on top of this or by pre-processing the quotation.
编辑:稍加努力,实际上就有可能再次使用query { .. }语法.您可以为整个查询表达式加引号并编写<@ query { .. } @>-这将无法直接工作,但是您可以将引号引出并提取查询的实际正文,然后将其直接传递给query.Run.这是适用于以上示例的示例:
With a bit more effort, it is actually possible to use the query { .. } syntax again. You can quote the entire query expression and write <@ query { .. } @> - this will not directly work, but you can then take the quotation and extract the actual body of the query and pass it to query.Run directly. Here is a sample that works for the above example:
open System.Linq open Microsoft.FSharp.Quotations open Microsoft.FSharp.Quotations.Patterns let runQuery (q:Expr<IQueryable<'T>>) = match q with | Application(Lambda(builder, Call(Some builder2, miRun, [Quote body])), queryObj) -> query.Run(Expr.Cast<Microsoft.FSharp.Linq.QuerySource<'T, IQueryable>>(body)) | _ -> failwith "Wrong argument" let test () = <@ query { for p in db.Products do where ((%predicate) p) select p.ProductName } @> |> runQuery |> Seq.iter (printfn "%s")更多推荐
如何在F#中组成查询表达式?
发布评论