Как сделать запрос с выражениями запроса f#?

Как мне сделать выражение запроса, похожее на SQL IN-запрос?

Я пытаюсь сделать что-то в этом роде:

let customerNumbers = set ["12345"; "23456"; "3456"]
let customerQuery = query {
    for c in dataContext.Customers do
    where(customerNumbers.Contains(c.CustomerNumber))
    select c
}

Но я получаю сообщение об ошибке:

System.NotSupportedException: Method 'Boolean Contains(System.String)' has no supported translation to SQL.

Изучите документацию по выражениям запросов по адресу http://msdn.microsoft.com/en-us/library/hh225374.aspx Я должен использовать другой запрос для части содержимого, но этот код не работает, пример не работает:

// Select students where studentID is one of a given list.
let idQuery = query { for id in [1; 2; 5; 10] do select id }
query { 
    for student in db.Student do
    where (idQuery.Contains(student.StudentID))
    select student
}

На самом деле idQuery не содержит никакого метода «Содержит».

Я также пробовал:

let customerNumbers = set ["12345"; "23456"; "3456"]
let customerQuery = query { 
    for c in dataContext.Customers do
    where (query { for x in customerNumbers do exists (c.CustomerNumber=x)})
    select r
}

Но это дает это сообщение об ошибке:

System.NotSupportedException: Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator

После еще нескольких тестов я заметил, что в дополнение к предложению Джина отлично работает следующее:

let customerNumbers = set ["12345"; "23456"; "3456"]
query {
    for customer in dataContext.Customer do
    where (query { for x in customerNumbers do contains customer.CustomerNumber})
    select customer
}

person NeoDarque    schedule 05.02.2014    source источник
comment
Я только что заметил, что мой первый пример, кажется, работает, если вместо этого я заменю набор списком, как ни странно.   -  person NeoDarque    schedule 05.02.2014
comment
Не могли бы вы включить полную трассировку стека для исключений, которые вы получаете? Это не поможет ответить на ваш вопрос, но мне любопытно посмотреть, ломается ли он в запросе F # -> уровень перевода LINQ или в LINQ -> перевод SQL.   -  person Jack P.    schedule 05.02.2014
comment
@JackP: пожалуйста.   -  person Gene Belitski    schedule 05.02.2014
comment
Это поддерживается в SQLProvider: github.com/fsprojects/SQLProvider   -  person Tuomas Hietanen    schedule 18.09.2016


Ответы (1)


Я считаю, что проблема связана с тем, как F# Set реализует метод Contains. Он относится к интерфейсу ICollection, и этот факт несколько огорчает построителя запросов LINQ-to-SQL.

Если вы явно добавите свой Contains в метод расширения территории IEnumerable, все будет в порядке:

let customerNumbers = set ["12345"; "23456"; "3456"]
let customerQuery = query {
    for c in dataContext.Customers do
    where((customerNumbers :> IEnumerable<string>).Contains(c.CustomerNumber))
    select c
}

Или, что то же самое, вы можете добавить запрос, отличный от LINQ-to-SQL.

let idQuery = query { for id in customerNumbers do select id }

у которого нет проблем с перечислением set, дающим seq<string>, а затем использовать его для Contains как

....
where (idQuery.Contains(c.CustomerNumber))
....

Или, для начала, вы можете оставить свой customerNumbers как seq:

let customerNumbers = set ["12345"; "23456"; "3456"] |> Set.toSeq

и использовать его как подсказки интуиции:

....
where(customerNumbers.Contains(c.CustomerNumber))
....
person Gene Belitski    schedule 05.02.2014