2011-02-10 4 views
3

Я работаю над проектом, в котором я пытаюсь использовать F # и Linq для UDF и хранимых процессов на SQL-сервере. Часть из них заключалась в том, чтобы статически определять все допустимые запросы, критерии сортировки и средство подсчета результатов запросов.составление многих цитат в запросы linq

Я до сих пор был довольно успешным, но у меня возникают серьезные трудности с составлением sortBy выражений.

Вот основная концепция

let sorter = 
    let exprMap:Map<string,Quotations.Expr<seq<Product> -> seq<Product>>> = 
    Map.ofList 
    ["ProductName",<@ Seq.sortBy (fun prod -> prod.Name) @> ] 
    // .. more entries .. 
    let sortBuilder sortkeys = 
     Array.foldBack 
     (fun criteria acc -> <@ %(exprMap.[criteria]) >> (%acc) @>) 
     sortkeys 
     <@ Seq.map id @> 

Это заканчивается используется позже исполнителю запроса как так

let execQuery = fun (predicates,sorts,scorer) -> 
    <@ seq { for prod in (%dc).Products do 
       if (%predicates) prod then yield prod } 
     |> (%sorts) 
     |> (%scorer) @> 

Используя эти основные контуры, все работает до тех пор, пока я не использовать (% сорта). Каждый раз, когда я пропускаю это, я не распознаю в F # переводчика Linq. Я пробовал несколько разных попыток использовать комбинаторы, но у меня есть смысл, что я чего-то не хватает. Если я отключу функцию сортировщика следующим образом:

<@ Seq.sortBy (fun prod -> prod.Name) |> Seq.sortBy (fun prod -> prod.Style) @> 

Работает должным образом. Однако с помощью комбинатора, как это:

let (|>*) = fun f g -> <@ fun c -> ((%f) c) |> (%g) @> 

не ..

Есть идеи?

ответ

1

К сожалению, у меня нет хорошего ответа на этот вопрос.

Боюсь, что переводчик F # LINQ в настоящее время очень чувствителен к структуре запроса. Используя композицию, вы должны иметь возможность получить ту же цитату, которую вы получаете, если пишете ее вручную, поэтому вам может понадобиться генерировать то же самое, что и работало, если оно было написано вручную.

Например, с вашего сортировщика, вам может понадобиться что-то вроде (я не пробовал, но я думаю, что это должно произвести точно такое же предложение, как обычный код, который работает):

let (|>*) f g = fun c -> <@ (%c) |> (%f) |> (%g) @> 

<@ seq { for prod in (%dc).Products do 
      if (%predicates) prod then yield prod } @> |> 
(<@ Seq.sortBy (fun prod -> prod.Name) @> |>* 
    <@ Seq.sortBy (fun prod -> prod.Style) @>) 

Проблема заключается в том, что если вы включаете лямбда-функции в цитату, переводчик F # должен иметь дело с ними - возможно, частично оценив их (потому что иначе переводчик LINQ to SQL завершится с ошибкой). В этом есть довольно много сложных случаев ...

Однако команда F # недавно делала некоторые улучшения в этой области. Я думаю, что лучше всего было бы найти простой пример для воспроизведения и отправить его на адрес fsbugs на microsoft dot com. Релизы PowerPack не являются «чувствительными», поэтому вы можете получить исходный код с последними изменениями, если вы спросите и предложите помощь при тестировании (но никаких обещаний).