我正在尝试使用最近推出的F#3.0查询理解语法来定义Bill of Materials类查询。虽然可以使用yield!
seq理解为内存中集合定义这些类型的查询,但我并不缺乏将它们转换为针对远程IQueryable源的查询理解。我想最难的是“训练”提供者从递归模式中识别公用表表达式。
有什么想法吗?
答案 0 :(得分:5)
不幸的是,我不认为F#3.0中当前的查询语法支持能够处理递归查询。主要问题是F#3.0依赖于主要为C#设计的标准IQueryable
实现,因此他们不期望递归结构。
我认为支持这一点非常困难。您可以为SQL转换器实现自己的F#引用(这很难),或者您可以实现某种预处理器,它采用包含递归的F#引用(查询)并将递归转换为LINQ to SQL转换器可以转换的内容处理(但这可能也很难)。
通常,方法是定义自己的查询构建器:
open System.IO
open Microsoft.FSharp.Quotations
type MyQueryBuilder() =
member x.For(a, body) = Seq.collect body a
member x.Quote(e) = e
member x.YieldFrom(s) = s
member x.Run(e:Expr<'T>) : 'T = failwithf "%A" e
// Example using the custom query builder
// (fails, printing the quoted query)
let mquery = MyQueryBuilder()
let n = [1 .. 10]
let rec nums a : seq<int> =
mquery { for b in n do
yield! nums b }
在Run
方法中,您会获得代表查询的报价单。您可以预处理它并使用对标准MyQueryBuilder
操作的调用替换对query
的所有调用,并用其他内容替换递归。然后,您可以致电query.Run
(运行标准IQueryable
实施)。
虽然正如我所说,这可能很难实现 - 但也许,如果你有一些你可以轻松处理的特定类型的递归,它可能是一个选择。但是,如果LINQ to SQL没有为任何标准模式生成公用表表达式,那么我认为你不能训练它来生成它们 - 据我所知,翻译器实际上并不是可扩展的。