c# - 在 `LINQ to Entities` 中使用 `System.String Concat` 会生成 `CAST`s 而不是 `CONCAT`
问题描述
正如我从文档中了解到的那样,当使用string.Concat
查询技术(例如 LINQ to Entities)时,此规范函数应转换为正在使用的提供程序的正确相应存储函数,即Concat
' MsSQL
s T-SQL
。但是当我运行以下测试代码时:
var items = (from item in testDB.Items
where list.Contains(string.Concat(item.Id,":"))
select new
{
Hit = string.Concat(item.Id,":"),
Item = item
}).ToList();
正在生成以下 SQL:
SELECT
[Extent1].[Id] AS [Id],
CAST( [Extent1].[Id] AS nvarchar(max)) + N':' AS [C1],
FROM [testDB].[Items] AS [Extent1]
WHERE (CAST([Extent1].[Id] AS nvarchar(max)) + N':' -- N.B.
IN (N'1:', N'2:', N'3:')) AND (CAST([Extent1].[Id] AS nvarchar(max)) + N':' IS NOT NULL)
注意:(+
加号运算符) withCAST
而不是Concat
正在使用。
显然我做错了什么,但是什么?问题是CAST
toNVARCHAR(MAX)
需要大量时间,尤其是在连接多个字段时。
看起来无法做到,因为Concat
使用了sql_variant
未定义的类型,因此SQLProviderManifest
不支持重载,因此只能映射一个函数签名(模式中的名称应该是唯一的),因此显然它们只是通过连接进行了短路在需要时使用带有强制转换的加号运算符,即使我Concat
首先映射 in 代码,生成SQL
的仍在使用它,所以它变得很明显。我认为唯一的方法是利用DbSet.SqlQuery
.
解决方案
所以为了让事情正常工作,我们不会使用LINQ
,但是DbSet.SqlQuery
:
var contains = list.Aggregate(new System.Text.StringBuilder(),
(sb, s) => sb.Append($"N'{s}', "),
sb => (sb.Length > 0)
? sb.ToString(0, sb.Length - 2)
: null);
if (contains == null)
{
//ToDo: list is empty, we've got a problem
}
else
{
var query = testDB.Items.SqlQuery($@"SELECT [E1].[Id],..
FROM [testDB].[Items] AS [E1]
WHERE CONCAT_WS(':', [E1].[Id],..) IN ({contains })");
}
当然应该用SqlParameter
s 来完成,但这是解决方法的一般思路。
推荐阅读
- sql - 使用了错误的 SQL 索引
- api - 从 xml 数组创建 GET 参数
- java - DatabaseHandler中的DatabaseHandler()不能应用于
- html - 如何更改语言和输入的开始日期?
- c++ - 命令行参数,cant 或两个变量
- wordpress - 应针对 woocommerce 中的 2 个不同类别应用两组不同的折扣
- python - 切菜板算法
- ruby - 检索步骤定义文件中的标记字符串
- ios - 将 IPA 上传到 App Store 时出错
- java - JDK8 RMI 服务器在 JDK9 或 JDK10 中不工作 - ClassNotFoundException