[英]String or binary data would be truncated WHERE IN
我得到SQL异常:
字符串或二进制数据将被截断
在SELECT中。 我读了几个带有相同标题的问题,但它们都是关于插入的。 我正在选择。
代码如下:
List<CategoryName> navigation = await db.Query<CategoryName>().FromSql(
$"WITH NestedCategories AS (
SELECT *
FROM Categories
WHERE Id IN (
{string.Join(",", products.Select(x =>
x.Categories.First().CategoryId).Distinct().Select(x => $"'{x}'"))}
)
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")
.AsNoTracking()
.ToListAsync();
如果我生成string.Join到控制台,然后将SQL命令放入Management Studio的查询窗口,我不会收到任何错误。 我得到了适当的结果。 问题显然在EF CORE中,我传递了太多的类别ID。 命令是根据Product-Category Id获取嵌套类别。
编辑:
public class CategoryName
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
}
编辑2 - 解决方案
string inClause = string.Join(",", products.Select(x => x.Categories.First().CategoryId).Distinct().Select(x => $"'{x}'"));
List<CategoryName> navigation = new List<CategoryName>();
using (DbCommand command = db.Database.GetDbConnection().CreateCommand())
{
command.CommandText = $"WITH NestedCategories AS (SELECT * FROM Categories WHERE Id IN ({inClause}) 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";
await db.Database.GetDbConnection().OpenAsync();
DbDataReader reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
navigation.Add(new CategoryName() { Id = reader.GetInt32(0), Name = reader.GetString(1), ParentId = await reader.IsDBNullAsync(2) ? null : await reader.GetFieldValueAsync<int?>(2) });
}
将FromSql
方法与内联插值SQL字符串一起使用时应该非常小心。
通常,插值字符串被解析为string
类型,但FromSql
方法具有FormattableString
参数的重载,这允许它在插值字符串中找到占位符并为每个字符串绑定命令参数 。
这通常是一种功能。 但是在你的情况下你只想把带有id的连接字符串嵌入到SQL字符串中,而EF为它创建一个参数,所以即使没有截断错误,查询也不会返回正确的结果,因为它会包含像WHERE IN (@param)
和@param
将包含永远不会匹配的逗号分隔文本。
最简单的解决方法是通过将SQL放在变量中来强制另一个FromSql
方法重载:
var sql = $"...";
List<CategoryName> navigation = await db.Query<CategoryName>().FromSql(sql)
// ...
或使用演员:
List<CategoryName> navigation = await db.Query<CategoryName>().FromSql((string)
$"...")
// ...
更好的方法是在SQL字符串中创建占位符({0},{1},...),并通过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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.