Как запретить ExecuteSqlInterpolated заключать строковые параметры в одинарные кавычки?

#c# #postgresql #.net-core #npgsql #ef-core-3.0

Вопрос:

У меня есть вызов в ядре EF 3 на сервер ProgresSQL, который имеет несколько строковых параметров. Одним из них является строка, представляющая собой объединение строк, уже заключенных в одинарные кавычки, как это:

 var listOfParams = "'a',','b','c'";
 

и позже перешел к запросу, который выглядит так:

 var id = "Customer1";
DbContext.Database.ExecuteSqlInterpolated(
   "SELECT ""CustomerNumber"" FROM dbo.""Customer"" 
      WHERE ""Id"" = {id} AND ""CustomerNumber"" IN ({listOfParams})");
 

Проблема в том, что, хотя идентификатор обертывания с кавычками верен, для второго параметра, который уже содержит кавычки, происходит какое-то второе обертывание или, возможно, экранирование одинарных кавычек, и это то, чего я хотел бы избежать.
И все же я не могу найти никакого относительно простого способа. Идеально, если можно сохранить listOfParams в качестве параметра SQL, в противном случае кэширование плана запроса было бы невозможным. Передача списка напрямую, похоже, тоже не работает. Похоже, ядро EF его не поддерживает.

Спасибо, Радек

Комментарии:

1. Совершенно неправильно заключать это в кавычки, и это не то, что ExecuteSqlInterpolated нужно. Он находит интерполяцию и изменяет ее на именованный параметр, что означает, что в итоге вы ""CustomerNumber"" IN (@listOfParams) получите то же ""CustomerNumber"" = @listOfParams самое, что и параметр, а параметр-это просто строка, в которой есть запятые, она никогда не будет интерпретироваться как список. Вам нужно использовать параметр JSON или a STRING_SPLIT или аналогичный в вашей переменной

2. @Charlieface: На самом деле ваш ответ навел меня на мысль. Я мог бы немного изменить запрос, чтобы включить следующее: выберите unnest(string_to_array({listOfParams},’,’)) в качестве «Номера пользователя», а затем используйте результат этого выбора во всех моих запросах. На самом деле я уже проверил его, и, похоже, он работает. Спасибо 🙂

3. Действительно, это один из методов, но вам нужно удалить кавычки и сделать это так ""CustomerNumber"" IN (select * from unnest(string_to_array({listOfParams}, ',')))

Ответ №1:

Вы пробовали просто использовать подход LINQ?

 var listOfParams =  "a b c".Split();
var r = DBContext.Customer
  .Where(c => c.Id == id amp;amp; listOfParams.Contains(c.CustomerNumber))
  .Select(c => c.CustomerNumber);
 

В SQLServer .Содержит сопоставляется с IN — PG, вполне может быть таким же

Комментарии:

1. Ну, сам запрос довольно сложный и, к сожалению, предотвращает использование Linq.

2. Вы должны опубликовать фактический запрос, чтобы мы могли предложить помощь в этом — нет смысла публиковать тупой вопрос, если вы не можете затем преобразовать любые тупые ответы обратно в сложный вариант. В наши дни можно смешивать n сопоставлять сложный SQL с LINQ

3. Я понимаю твою точку зрения. Позвольте мне попробовать одно решение, каким-то образом предложенное Charlieface, и если я снова застряну, я предоставлю полный запрос (немного запутанный, конечно).

Ответ №2:

Если то, что вы ищете, — это параметризация вашего списка ( a, b, c ), то вы, вероятно, захотите передать параметр массива-это должно полностью поддерживаться Npgsql и поставщиком ядра EF, а также правильно использовать планы запросов/подготовленные инструкции.

Обратите внимание, что для массивов вам нужно использовать = ANY (<array>) конструкцию PG, а не IN .

 var id = "Customer1";
var listOfParams = new[] { "a", "b", "c" };

DbContext.Database.ExecuteSqlInterpolated(
   "SELECT ""CustomerNumber"" FROM dbo.""Customer"" 
      WHERE ""Id"" = {id} AND ""CustomerNumber"" = ANY ({listOfParams})");