为什么在linq-to-sql选择中比较UTF16字符串时会得到错误的结果?
本文关键字:错误 结果 字符串 linq-to-sql 选择 UTF16 比较 为什么 | 更新日期: 2023-09-27 18:08:03
我使用c#和。net 4.0与MS SQL 2008。
我正在运行一个集成测试来验证数据是否得到正确的存储和检索。它往往会失败。当我查看它时,我发现从linq-to-sql调用返回的值是错误的。我对linq-to-sql语句进行了分析,发现在Server Management Studio中,被分析的SQL返回错误的值,而具有相同参数的手动输入查询工作正确。
sql查询和结果:
exec sp_executesql N'SELECT TOP (1) [t0].[ID], [t0].[UserName], [t0].TCID
FROM [dbo].[Users] AS [t0]
WHERE ([t0].[TCID] = @p0) AND ([t0].[UserName] = @p1)',N'@p0 int,@p1
nvarchar(4000)',@p0=8,@p1=N'ҭРӱґѻ'
在 搜索结果
ID UserName TCID
2535 ҭРґѻӱ 8
如您所见,UserName与相等性检查中的内容不匹配。
如果我这样做,我得到预期的结果:
SELECT TOP 1000 [ID]
,[UserName]
,[TCID]
FROM [dbo].[Users]
where TCID=8 and username = 'ҭРӱґѻ'
I get back:
ID UserName TCID
正确。
UserName is nvarchar(50), ID和TCID为int。
知道为什么第一个查询得到错误的结果吗?
你没有得到第二个查询的结果,因为你忘记了前缀n的参数,我打赌你得到的结果就像与动态SQL如果你使用:
SELECT TOP 1000 [ID]
,[UserName]
,[TCID]
FROM [dbo].[Users]
where TCID=8 and username = N'ҭРӱґѻ'; -- note the N prefix here
现在,我并不是说您应该得到一个结果,但这应该使您的两个测试方法之间的行为一致。列的排序规则是什么?您可以通过指定二进制排序来"修复"这个问题。例如,这应该产生正确的行为:
SELECT COUNT(*)
FROM [dbo].[Users]
WHERE [UserName] = N'ҭРӱґѻ' COLLATE Latin1_General_BIN;
-- 0
SELECT COUNT(*)
FROM [dbo].[Users]
WHERE [UserName] = N'ҭРґѻӱ' COLLATE Latin1_General_BIN;
-- 1
对于正在使用的排序规则(可能是SQL server特定的排序规则),没有定义一些Unicode代码点。因此,SQL Server将它们视为空字符串:
SELECT CASE WHEN N'ӱ' COLLATE SQL_Latin1_General_CP1_CI_AS = N " THEN 'YES' ELSE 'NO' END
如果我们使用较新的Windows排序规则,如Cyrillic_General_100_CI_AS,我们会看到这些字符串不匹配:
当N'ӱ' COLLATE Cyrillic_General_100_CI_AS = N " THEN 'YES' ELSE 'NO' END