#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 или aSTRING_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})");