Как мне использовать «Где В» в Dapper

21

Я уже некоторое время безуспешно пытаюсь использовать IEnumerable<string> с предложением WHERE IN в Dapper.

В документации сказано, что IEnumerable<int> поддерживается для использования в WHERE IN , но я даже не могу заставить это работать.

Dapper allow you to pass in IEnumerable<int> and will automatically parameterize your query.

Сообщение об ошибке, которое я получаю, является синтаксической ошибкой Sql. Incorrect syntax near ','.

Я собрал некоторый тестовый код, который, я надеюсь, продемонстрирует то, чего я пытаюсь достичь.

string connString = "Server=*.*.*.*;Database=*;User Id=*;Password=*;";

string sqlStringIn = @"SELECT StringText FROM 
                (SELECT 1 ID, 'A' StringID, 'This is a test' StringText
                UNION SELECT 2 ID, 'B' StringID, 'Another test' StringText
                UNION SELECT 3 ID, 'C' StringID, 'And another' StringText
                UNION SELECT 4 ID, 'D' StringID, 'and again' StringText
                UNION SELECT 5 ID, 'E' StringID, 'yet again' StringText) data
                WHERE StringId IN (@str)";

string sqlIntegerIn = @"SELECT StringText FROM 
                (SELECT 1 ID, 'A' StringID, 'This is a test' StringText
                UNION SELECT 2 ID, 'B' StringID, 'Another test' StringText
                UNION SELECT 3 ID, 'C' StringID, 'And another' StringText
                UNION SELECT 4 ID, 'D' StringID, 'and again' StringText
                UNION SELECT 5 ID, 'E' StringID, 'yet again' StringText) data
                WHERE ID IN (@integer)";


using (SqlConnection conn = new SqlConnection(connString))
{
    conn.Open();

    List<int> integers = new List<int>{ 1, 2, 3 };
    List<string> strings = new List<string> { "A", "B", "C" };

    var parameters = new {str = strings, integer = integers };

    //fails here
    IEnumerable<string> intTest = conn.Query<string>(sqlIntegerIn, parameters, commandType: System.Data.CommandType.Text);

    //and here
    IEnumerable<string> stringTest = conn.Query<string>(sqlStringIn, parameters, commandType: System.Data.CommandType.Text);

}
    
задан Sam 12.11.2013 в 16:10
источник
  • Почему вы не используете Linq? Для Dapper есть вспомогательная библиотека, которая выполняет эту работу: sqlinq.codeplex.com/releases/view/88056 –  Aybe 12.11.2013 в 19:00
  • @ Не нужно; dapper явно обрабатывает эту ситуацию –  Marc Gravell♦ 12.11.2013 в 20:43

2 ответа

47

Чтобы сделать то, что нужно здесь, dapper должен изменить SQL на лету - поэтому он должен быть действительно уверен, что он делает правильные вещи. Обычный правильный синтаксис SQL включает круглые скобки:

WHERE StringId IN (@str)

Чтобы устранить неоднозначность, используйте синтаксис voodoo dapper опускает круглые скобки:

WHERE StringId IN @str

Если это обнаруживается, он ищет параметр с именем str и расширяет его до одного из:

WHERE 1=0 -- if no values
WHERE StringId = @str -- if exactly one value
WHERE StringId IN (@str0, @str1, ...) -- if more than one value

Но короткая версия: удалите скобки.

    
ответ дан Marc Gravell 12.11.2013 в 20:41
  • @Marc не падает, если список превышает максимальный? См. Сообщение об ошибке: входящий запрос имеет слишком много параметров. Сервер поддерживает максимум 2100 –  cs0815 20.10.2014 в 16:27
  • @csetzkorn, если вы используете очень большие наборы, TVP и INNER JOIN, вероятно, намного лучше, чем IN; dapper имеет полную поддержку TVP. То, что я не хочу делать, - это жесткое программирование различных технических ограничений каждого поставщика в библиотеке –  Marc Gravell♦ 20.10.2014 в 16:35
  • Спасибо, TVP звучит хорошо. Полагаю, я могу просто включить его в свой параметризованный sql? (например, stackoverflow.com/questions/26466485/...) –  cs0815 20.10.2014 в 16:37
  • @csetzkorn довольно много: stackoverflow.com/a/24633764/23354 –  Marc Gravell♦ 20.10.2014 в 18:46
  • Спасибо. Я все еще не уверен, как это сделать. Можете ли вы посмотреть: stackoverflow.com/questions/26468710/... –  cs0815 20.10.2014 в 18:51
Показать остальные комментарии
1

Я хочу добавить важное примечание, если вы заинтересованы в возможности обработки пустого списка, иначе сделайте IN clause optional . Я сделал это, добавив свойство, содержащее счетчик, например public int InClauseCount => InClauseList?.Length ?? 0;

Затем используйте счет в sql следующим образом ...

Select field1, field2
from Table1
where (some condition)
AND (@InClauseCount = 0 OR field1 IN @InClauseList)

Я надеюсь, что это может кому-то помочь. Я потратил немного времени, пытаясь решить эту проблему, частично потому что я новичок в Dapper.     

ответ дан user1856792 29.11.2017 в 12:45