2012-04-15 79 views

回答

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,所以有可能使用與the one that I implemented for C#相同的技巧。不過,我想有些細節可能會有所不同,所以我不會期望它能立即工作。這個想法的最佳實現是在LINQKit,但我認爲它不會直接在F#中工作。

所以,一般來說,我認爲唯一可行的例子就是第一個例子 - 通過編寫多個查詢來將其他查詢操作符應用於查詢。

11

我們最近開發了一個庫,FSharpComposableQuery,旨在支持F#3.0及更高版本中更靈活的查詢表達式組合。它旨在作爲重載標準查詢構建器的插入替換。

托馬斯的實例可以進行如下修改:

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) } 

它(在托馬斯的原始代碼)將有可能通過加載所有的產品到內存中,並在內存中做選擇進行評估,而我們真正想要的是一樣的東西:

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

這將變成一個SQL查詢的選擇。 FSharpComposableQuery優先於QueryBuilder執行此操作以及其他轉換。所以,查詢可以更自由地使用引用和反引用來組成。

項目主頁是在這裏:http://fsprojects.github.io/FSharp.Linq.ComposableQuery/

並沒有我只是提供給有關動態查詢,另一個(舊)的問題在回答中一些更多的討論:How do you compose query expressions in F#?

意見或問題(特別是如果事情休息或者你認爲應該工作的東西不會)非常受歡迎。

[編輯:更新了項目頁面的鏈接,這些鏈接剛剛更改爲刪除單詞「Experimental」。]