4

我曾尝试使用 FLINQ,但它与 F# 3.0 beta 相比已经过时了。

有人可以给我一些关于如何在 F# 中创建动态 SQL 查询的指示吗?

4

2 回答 2

11

我们最近开发了一个库,FSharpComposableQuery旨在支持 F# 3.0 及更高版本中更灵活的查询表达式组合。它旨在作为重载标准查询构建器的直接替代品。

Tomas 的例子可以修改如下:

open FSharpComposableQuery

// Initial query that simply selects products
let q1 = 
  <@ query { for p in ctx.Products do 
             select p }  @>

// Create a new query that specifies only expensive products
let q2 = 
  query { for p in %q1 do
          where (p.UnitPrice.Value > 100.0M) }

这只是引用查询表达式并将其拼接到第二个查询中。但是,这会导致带引号的查询表达式,默认QueryBuilder可能无法转换为单个查询,因为q2计算结果为(等效)表达式

query { for p in (query { for p in ctx.Products do 
                          select p }) do
        where (p.UnitPrice.Value > 100.0M) }

其中(如在 Tomas 的原始代码中)可能会通过将所有产品加载到内存中并在内存中进行选择来评估,而我们真正想要的是:

query { for p in ctx.Products do
        where (p.UnitPrice.Value > 100.0M) }

这将变成一个 SQL 选择查询。 FSharpComposableQuery覆盖QueryBuilder以执行此转换以及其他转换。因此,可以更自由地使用引用和反引用来组合查询。

项目主页在这里: http: //fsprojects.github.io/FSharp.Linq.ComposableQuery/

在我刚刚提供给另一个(旧)关于动态查询的问题的答案中还有一些讨论:你如何在 F# 中编写查询表达式?

非常欢迎发表评论或提出问题(特别是如果出现问题或您认为应该起作用的东西不起作用)。

[编辑:更新了项目页面的链接,这些页面刚刚更改为删除“实验”一词。]

于 2014-07-30T11:18:38.293 回答
5

在 F# 3.0 中,查询是自动引用的,因此您不能使用<@ foo %bar @>使组合查询成为可能的引号拼接(语法)。您可以通过使用拼接组合查询来编写的大部分内容仍然可以通过从先前的源创建新查询并添加即过滤以“通常的 LINQ 方式”完成:

// Initial query that simply selects products
let q1 = 
  query { for p in ctx.Products do 
          select p }

// Create a new query that specifies only expensive products
let q2 = 
  query { for p in q1 do
          where (p.UnitPrice.Value > 100.0M) }

这样,您可以动态添加条件、动态指定投影(使用select)并执行其他一些查询组合。但是,您无法像使用显式引用那样获得编写查询的全部灵活性。我想这是 F# 3.0 必须为类似于 C# 中存在的更简单的语法付出的代价。

原则上,您应该能够使用query.Select(等)运算符显式编写查询。这将使用显式引用来编写,因此您应该能够使用拼接。但是,我不完全知道翻译是如何工作的,所以我不能给你一个工作样本。像这样的东西应该可以工作(但语法非常难看,所以最好只使用字符串或其他一些技术):

<@ query.Select(Linq.QuerySource<_, _>(ctx.Products), fun prod -> 
     // You could use splicing here, for example, if 'projection' is
     // a quotation that specifies the projection, you could write:
     //   %projection
     prod.ProductName) @>
|> query.Run

F# 3.0 中的查询基于IQueryable,因此可以使用与我为 C# 实现的技巧相同的技巧。但是,我想某些细节会有所不同,所以我不希望它立即起作用。该想法的最佳实现是在LINQKit中,但我认为它不会直接在 F# 中工作。

因此,总的来说,我认为唯一有效的情况是第一个示例 - 您只需通过编写多个查询将其他查询运算符应用于查询。

于 2012-04-15T12:11:27.500 回答