Linq查询的行为不符合预期
我有一个非常简单的linq查询,如下所示:
var result = (from r in employeeRepo.GetAll() where r.EmployeeName.Contains(searchString) || r.SAMAccountName.Contains(searchString) orderby r.EmployeeName select new SelectListItem { Text = r.EmployeeName, Value = r.EmployeeName });
这个问题是出于一些奇怪的原因,它把我搜索的每个人的记录都记录下来,无论是小写还是大写。 即
- 测试用户
- 测试用户
- 测试用户
我会找回正确的记录。 然而,当我使用小写字母搜索我自己的名字时,我没有得到任何结果,但如果我使用我的名字的第一个字母作为大写,那么我得到结果。 我似乎无法弄清楚为什么这样做。
数据库中的每个名字和姓氏都以大写字母开头。
我正在使用的searchString是:
-
richard
– 我得到了正确的结果 -
waidande
– 未找到结果
上述两个用户都在数据库中。
我也使用Entity Framework
来查询Sql Server 2012
。
如果您的文本具有NVARCHAR
数据类型,请检查实际上不相同的类似字母:
CREATE TABLE #employee (ID INT IDENTITY(1,1), EmployeeName NVARCHAR(100)); INSERT INTO #employee(EmployeeName) VALUES (N'waidаnde'); SELECT * FROM #employee WHERE EmployeeName LIKE '%waidande%'; -- checking SELECT * FROM #employee WHERE CAST(EmployeeName AS VARCHAR(100)) <> EmployeeName;
LiveDemo
这里: 'а'
!= 'a'
。 一个来自Cyrillic
'a'
,第二个是正常的。
理念取自:
幻灯片: http : //sqlbits.com/Sessions/Event12/Revenge_The_SQL
PS我强烈建议观看Rob Volk的演讲: Revenge: The SQL!
。
要解决此问题,请确定问题是在EF端还是在DB端。 一个常见的错误是额外的空格,所以在继续之前确保不是这种情况。
首先检查EF生成的查询,您可以使用以下方法之一来执行此操作
- ObjectQuery.ToTraceString()方法
- 拦截数据库调用的EF日志记录
- Sql server profiler
如果您正确使用EF并且您的查询按预期转换为SQL并且在where部分中包含谓词,但您仍然没有获得任何有意义的结果,这里有一些想法在DB端尝试:
- 检查排序规则 (请注意,可以在服务器,数据库和单个列级别设置) – 注意区分大小写和正在使用的代码页
- validation您的搜索字符串是否包含可在db代码页中解释的符号 – 例如,如果代码页为252 – Windows Latin 1 ANSI并且您发送带有UTF-16符号的输入,这些符号在ANSI之外 – 您将无法获得任何结果,即使符号看起来相同
- 非常不可能,但作为最后的手段,请检查您的某个查询是否未被缓存,如此处所述
默认情况下,SQL Server 2012(SQL Server)安装时使用不区分大小写的排序规则。 如果需要使用区分大小写从数据库中检索记录(因为您有“几个”记录),则需要更改排序规则(请注意,因为如果更改DBMS排序规则,则还要更改主数据库排序规则,因此表和字段名称也会变为大小写敏感)。
如果您不需要避免从DBMS中检索所有记录,则可以在检索它们之后过滤记录,即
var result = (from r in employeeRepo.GetAll() where r.EmployeeName.Contains(searchString) || r.SAMAccountName.Contains(searchString) orderby r.EmployeeName select new SelectListItem { Text = r.EmployeeName, Value = r.EmployeeName }) .ToList() // Materialize records and apply case sensitive filter .Where(r.EmployeeName.Contains(searchString) || r.SAMAccountName.Contains(searchString));