Скомпилированные запросы 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 ответа

Как и пост, на который вы ссылались, это не возможно из коробки. В посте также упоминается создание вашего собственного поставщика запросов, но это немного сложнее и сложнее, что вам, вероятно, не нужно.

У вас есть несколько вариантов здесь:

  1. Не используйте скомпилированный запрос. Скорее, есть метод, который создаст предложение where из каждого элемента в массиве, что приведет к чему-то вроде этого (псевдо-код):

    where 
        online[0] == u.username ||
        online[1] == u.username ||
        ...
        online[n] == u.username
    

    Обратите внимание, что вам придется использовать выражение здесь для создания каждого предложения OR.

  2. Если вы используете 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".

Надеюсь, что это поможет кому-то!

Другие вопросы по тегам