Вы должны быть очень осторожны при использовании метода FromSql
со встроенной интерполированной строкой SQL.
Обычно интерполированные строки разрешаются в тип string
, но метод FromSql
имеет перегрузку с параметром FormattableString
, что позволяет ему находить заполнители внутри интерполированной строки и связывает параметр команды для каждого из них.
Обычно это функциональность.Но в вашем случае вы хотите, чтобы в строку SQL встраивалась только объединенная строка с идентификаторами, в то время как EF создает для нее параметр, поэтому даже если не было ошибки усечения, запрос не будет возвращать правильные результаты, поскольку он будет содержатьчто-то вроде WHERE IN (@param)
и @param
будет содержать разделенный запятыми текст, который никогда не будет совпадать.
Самое простое решение - принудительно перегрузить другой метод FromSql
, поместив SQL в переменную:
var sql = $"...";
List<CategoryName> navigation = await db.Query<CategoryName>().FromSql(sql)
// ...
или используйте оператор приведения:
List<CategoryName> navigation = await db.Query<CategoryName>().FromSql((string)
$"...")
// ...
Лучшим подходом будет создание заполнителей ({0}, {1}, ...) внутри строки SQL и передача значений через params object[] parameters
аргумент.Таким образом, EF Core будет связывать параметр для каждого значения (например, WHERE IN (@p0, @p1, ...)
), а не для встроенных констант:
var parameters = products.Select(x => x.Categories.First().CategoryId).Distinct()
.Cast<object>().ToArray(); // need object[]
var placeholders = string.Join(",", Enumerable.Range(0, parameters.Length)
.Select(i = "{" + i + "}"));
var sql =
$"WITH NestedCategories AS (
SELECT *
FROM Categories
WHERE Id IN ({placeholders})
UNION ALL
SELECT t.*
FROM Categories t
INNER JOIN NestedCategories c On c.ParentId = t.Id
)
SELECT DISTINCT c.Id, c.Name, c.ParentId
FROM NestedCategories c";
var query = db.Query<CategoryName>().FromSql(sql, parameters);