以编程方式构造计算表达式

时间:2016-08-17 12:28:48

标签: f#

我想创建一个方法,它可以从提供的数据结构中构造一个等效的query { ... }计算表达式(使用FSharp.Data.TypeProviders与LINQ2SQL或LINQ2Entities),即:

Collection("customers", [ 
    Field "customerId"; 
    Collection("orders", [ 
        Field "orderId" ]) ])

为此,我需要了解查询如何首先转换为代码。以下面的查询为例:

query {
    for c in db.Customers do
    select (c.CustomerID, query {
        for o in c.Orders do
        select o.OrderID
    } |> Seq.toList)
} 

没有计算表达式语法会是什么样子?

2 个答案:

答案 0 :(得分:4)

我不建议以编程方式生成F#查询。

查询的主要目的是使编写漂亮的F#源代码成为可能。执行它们时,您编写的代码首先会转换为LINQ样式的表达式树,然后将其转换为SQL查询。如果您设法将查询规范翻译为F#查询,则可以使用以下内容:

 +------------+    +----------+    +----------------------+    +-----+
 | Your query | -> | F# query | -> | LINQ expression tree | -> | SQL |
 +------------+    +----------+    +----------------------+    +-----+

多次转换没有任何问题,但是有很多事情使得通过F#查询的路径变得更加复杂:

  • 在您的查询格式中,事物似乎表示为字符串。所以,你需要从字符串转到.NET MethodInfo只是为了回到字符串。

  • 使用F#queries / LINQ,您可以获得类型化对象,这是主要优点之一,但如果您动态构建查询,那么您只需返回{{1}的序列值 - 并且必须使用反射或类似的东西来访问它们。

TL; DR - 我认为直接获取查询表示并生成SQL要容易得多。转换的结构类似于生成F#查询,但您不必乱用引号和反射。

答案 1 :(得分:4)

如果你想看看有什么东西脱毒,只需把它放到报价单中。如果您使用您的示例执行此操作,您将看到

indexOf

大致相当于

<@ 
    query {
        for c in db.Customers do
        select (c.CustomerID, query {
            for o in c.Orders do
            select o.OrderID
        } |> Seq.toList)
    } 
@>

(我清理了一些无关的变量)。我同意托马斯的看法,可能有更好的方法来实现你想要的东西而不是直接创建这样的表达式。