Скомпилированные запросы Linq и int[] в качестве параметра
Я использую следующий LINQ to SQL скомпилированный запрос.
private static Func<MyDataContext, int[], int> MainSearchQuery =
CompiledQuery.Compile((MyDataContext db, int[] online ) =>
(from u in db.Users where online.Contains(u.username)
select u));
Я знаю, что невозможно использовать параметр ввода последовательности для скомпилированного запроса, и я получаю сообщение об ошибке "Параметры не могут быть последовательностями" при его запуске.
В другом сообщении здесь я видел, что есть какое-то решение, но я не мог его понять.
Кто-нибудь знает использовать компилированный запрос с массивом в качестве входного параметра?
Пожалуйста, разместите пример, если вы делаете.
2 ответа
Как и пост, на который вы ссылались, это не возможно из коробки. В посте также упоминается создание вашего собственного поставщика запросов, но это немного сложнее и сложнее, что вам, вероятно, не нужно.
У вас есть несколько вариантов здесь:
Не используйте скомпилированный запрос. Скорее, есть метод, который создаст предложение where из каждого элемента в массиве, что приведет к чему-то вроде этого (псевдо-код):
where online[0] == u.username || online[1] == u.username || ... online[n] == u.username
Обратите внимание, что вам придется использовать выражение здесь для создания каждого предложения OR.
Если вы используете SQL Server 2008, создайте скалярную функцию, которая будет принимать табличный параметр и значение для повторного сравнения. Он вернет немного (чтобы указать, есть ли элемент в значениях в таблице). Затем представьте эту функцию через LINQ-to-SQL в вашем контексте данных. Оттуда вы сможете создать CompiledQuery для этого. Обратите внимание, что в этом случае вы должны взять
IEnumerable<string>
(при условии, что имя пользователя имеет тип string) вместо массива, просто потому, что у вас может быть более одного способа представления последовательности строк, и для SQL-сервера для этой операции не будет иметь значения, каков порядок.
Одно из решений, которое я нашел (MS MS 2005/2008). И я не уверен, что это уместно во всех сценариях - просто написать динамический sql и выполнить его для datacontext, используя метод ExecuteQuery.
Например, если у меня есть неограниченный список, который я пытаюсь передать в запрос, чтобы сделать содержит...
' Mock a list of values
Dim ids as New List(of Integer)
ids.Add(1)
ids.Add(2)
' ....
ids.Add(1234)
Dim indivs = (From c In context.Individuals _
Where ids.Contains(c.Id) _
Select c).ToList
Я бы изменил этот запрос, чтобы создать строку SQL для непосредственного выполнения с базой данных, например...
Dim str As New Text.StringBuilder("")
Dim declareStmt as string = "declare @ids table (indivId int) " & vbcrlf)
For i As Integer = 0 To ids.Count - 1
str.Append("select " & ids(i).ToString() & " & vbcrlf)
If i < ids.Count Then
str.Append("union " & vbcrlf)
End If
Next
Dim selStatement As String = "select * From " & context.Mapping.GetTable(GetType(Individuals)).TableName & _
" indiv " & vbcrlf & _
" inner join @ids ids on indiv.id = ids.id"
Dim query = declareStmt & str.ToString & selStatement
Dim result = context.ExecuteQuery(of Individual)(query).ToList
Таким образом, за исключением любых синтаксических ошибок или ошибок, которые я кодировал (выше приведен более или менее псевдо-код и не тестировался), выше будет генерировать табличную переменную в SQL и выполнять внутреннее соединение с требуемой таблицей (в этом примере отдельные лица) и избегать использование оператора "IN".
Надеюсь, что это поможет кому-то!