简体   繁体   English

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

[英]Dynamic SQL queries with F# 3.0?

I have tried to use FLINQ but it is rather out of date with F# 3.0 beta. 我曾尝试使用FLINQ,但它与F#3.0测试版相比已经过时了。

Can someone give me some pointers on how to create dynamic SQL queries in F#? 有人可以给我一些关于如何在F#中创建动态SQL查询的指针吗?

We have recently developed a library, FSharpComposableQuery , aimed at supporting more flexible composition of query expressions in F# 3.0 and above. 我们最近开发了一个库FSharpComposableQuery ,旨在支持F#3.0及更高版本中更灵活的查询表达式组合。 It's intended as a drop-in replacement overloading the standard query builder. 它旨在作为重载标准查询构建器的替代品。

Tomas's example can be modified as follows: 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) }

This simply quotes the query expression and splices it into the second query. 这只是引用查询表达式并将其拼接到第二个查询中。 However, this results in a quoted query expression that the default QueryBuilder may not be able to turn into a single query, because q2 evaluates to the (equivalent) expression 但是,这会导致引用的查询表达式,默认的QueryBuilder可能无法转换为单个查询,因为q2计算为(等效)表达式

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

which (as in Tomas's original code) will likely be evaluated by loading all of the products into memory, and doing the selection in memory, whereas what we really want is something like: 哪个(如在Tomas的原始代码中)可能会通过将所有产品加载到内存中,并在内存中进行选择来评估,而我们真正想要的是:

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

which will turn into an SQL selection query. 这将变成SQL选择查询。 FSharpComposableQuery overrides the QueryBuilder to perform this, among other, transformations. FSharpComposableQuery重写QueryBuilder以执行此转换。 So, queries can be composed using quotation and antiquotation more freely. 因此,查询可以更自由地使用引用和反引号组成。

The project home page is here: http://fsprojects.github.io/FSharp.Linq.ComposableQuery/ 项目主页在这里: http//fsprojects.github.io/FSharp.Linq.ComposableQuery/

and there is some more discussion in an answer I just provided to another (old) question about dynamic queries: How do you compose query expressions in F#? 在我刚刚提供的关于动态查询的另一个(旧)问题的答案中还有一些讨论: 如何在F#中编写查询表达式?

Comments or questions (especially if something breaks or something that you think should work doesn't) are very welcome. 评论或问题(特别是如果出现问题或者您认为应该工作的事情不是这样)是非常受欢迎的。

[EDIT: Updated the links to the project pages, which have just been changed to remove the word "Experimental".] [编辑:更新了项目页面的链接,这些链接刚刚更改为删除“实验”一词。]

In F# 3.0, the query is quoted automatically and so you cannot use quotation splicing (the <@ foo %bar @> syntax) that makes composing queries possible. 在F#3.0中,查询是自动引用的,因此您不能使用引号拼接( <@ foo %bar @>语法)来使编写查询成为可能。 Most of the things that you could write by composing queries using splicing can still be done in the "usual LINQ way" by creating a new query from the previous source and adding ie filtering: 通过使用拼接编写查询可以编写的大多数内容仍然可以通过从前一个源创建新查询并添加即过滤来以“通常的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) }

This way, you can dynamically add conditions, dynamically specify projection (using select ) and do a couple of other query compositions. 这样,您可以动态添加条件,动态指定投影(使用select )并执行其他几个查询组合。 However, you don't get the full flexibility of composing queries as with explicit quotations. 但是,与显式引用一样,您无法充分灵活地编写查询。 I guess this is the price that F# 3.0 has to pay for a simpler syntax similar to what exists in C#. 我想这是F#3.0必须为类似于C#中存在的更简单的语法付出的代价。

In principle, you should be able to write query explicitly using the query.Select (etc.) operators. 原则上,您应该能够使用query.Select (etc.)运算符显式编写查询。 This would be written using explicit quotations and so you should be able to use splicing. 这将使用显式引用编写,因此您应该能够使用拼接。 However, I don't exactly know how the translation works, so I can't give you a working sample. 但是,我并不完全知道翻译是如何工作的,所以我不能给你一个工作样本。 Something like this should work (but the syntax is very ugly, so it is probably better to just use strings or some other techniques): 像这样的东西应该工作(但语法非常难看,所以最好只使用字符串或其他技术):

<@ 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

The queries in F# 3.0 are based on IQueryable , so it might be possible to use the same trick as the one that I implemented for C# . F#3.0中的查询基于IQueryable ,因此可能使用与我为C#实现的技巧相同的技巧。 However, I guess that some details would be different, so I wouldn't expect that to work straight away. 但是,我猜有些细节会有所不同,所以我不希望它能立即发挥作用。 The best implementation of that idea is in LINQKit , but I think it won't directly work in F#. 这个想法的最佳实现是在LINQKit ,但我认为它不会直接在F#中工作。

So, in general, I think the only case that works well is the first example - where you just apply additional query operators to the query by writing multiple queries. 因此,一般来说,我认为唯一适用的情况是第一个示例 - 您只需通过编写多个查询将其他查询运算符应用于查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM