使用F#3.0进行动态SQL查询?

Art*_*eef 4 sql f#

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

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

Jam*_*ney 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) }
Run Code Online (Sandbox Code Playgroud)

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

query { for p in (query { for p in ctx.Products do 
                          select p }) do
        where (p.UnitPrice.Value > 100.0M) }
Run Code Online (Sandbox Code Playgroud)

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

query { for p in ctx.Products do
        where (p.UnitPrice.Value > 100.0M) }
Run Code Online (Sandbox Code Playgroud)

这将变成SQL选择查询. FSharpComposableQuery覆盖QueryBuilder执行此操作以及其他转换.因此,查询可以更自由地使用引用和反引号组成.

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

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

评论或问题(特别是如果出现问题或者您认为应该工作的事情不是这样)是非常受欢迎的.

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


Tom*_*cek 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) }
Run Code Online (Sandbox Code Playgroud)

这样,您可以动态添加条件,动态指定投影(使用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
Run Code Online (Sandbox Code Playgroud)

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

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