我正在为库存表的仓库服务编写查询。仅供参考:我们正在使用C#7.0,EF 6,并且正在使用Moq来测试查询。
我了解到,将string.Contains(...)
(默认情况下区分大小写)放入LINQ查询中,然后转换为SQL时,结果是区分大小写的( in )(找到其他SO帖子)以帮助解决该问题,我们将对其进行处理),我还发现,当参数为string.Contains(...)
并转换为小写字母时,string.Empty
函数似乎有一个怪癖(发现没有关于此的帖子)。
尝试使用不区分大小写的字符串。当LINQ to Entities尝试转换为SQL时,Contains(...)重载会被抛出异常,因此我必须手动指定column.Contains(argument.ToLower())
以便两者LINQ to Entities的SQL查询可按预期的和操作,以进行不区分大小写的模拟单元测试。
问题::如果参数为string.Empty,则不匹配任何内容。罪魁祸首是何时将参数转换为小写。
这不是障碍(只需将argument.ToLower()
检查移到查询外部即可解决此问题,无论如何它的效率都会提高一点),但我仍然想知道最新情况。
public List<InventoryModel> FindByTrackingNumberSubstring( string substring )
{
// (bad) matches nothing when argument is string.Empty
//var query = _modelTable.Where( entity => entity.Tracking_Number.ToLower().Contains( substring.ToLower() ) );
// (good) matches everything when argument is string.Empty
string lower = substring.ToLower();
var query = _modelTable.Where( entity => entity.Tracking_Number.ToLower().Contains( lower ) );
return query.ToList<InventoryModel>();
}
// SQL for queries 1 and 2, respectively (stripped out SELECT and FROM stuff for brevity)
WHERE ((CASE WHEN (( CAST(CHARINDEX(LOWER(@p__linq__0), LOWER([Extent1].[Tracking Number])) AS int)) > 0) THEN cast(1 as bit) WHEN ( NOT (( CAST(CHARINDEX(LOWER(@p__linq__0), LOWER([Extent1].[Tracking Number])) AS int)) > 0)) THEN cast(0 as bit) END) = 1)
WHERE ((CASE WHEN (LOWER([Extent1].[Tracking Number]) LIKE @p__linq__0 ESCAPE N'~') THEN cast(1 as bit) WHEN ( NOT (LOWER([Extent1].[Tracking Number]) LIKE @p__linq__0 ESCAPE N'~')) THEN cast(0 as bit) END) = 1)
我做了一些检查,发现在LINQ to Entities的SQL查询中,string.Contains(string.Empty)
匹配任何东西,而我发现string.Empty.ToLower() == string.Empty
匹配任何东西,但是将两者与C#和LINQ放在一起实体分歧。在前一种情况下,string.Contains(string.Empty.ToLower())
匹配任何内容(按预期方式),而在后一种情况下,则不匹配任何内容。
为什么?
答案 0 :(得分:2)
我认为这将是EF的SQL Server提供程序的一个怪癖,因为当您对条件和要比较的字段执行.ToLower()
时,它会将请求识别为明显不区分大小写,并替换了LIKE使用CHARINDEX比较进行查询,该比较不能以相同方式处理SQL Server中的空字符串。区分大小写的行为将取决于数据库引擎,对于SQL Server,则取决于为数据库中的字符串选择的排序规则。不确定为什么不能使用像LOWER(Tracking_Number)这样的LOWER('%%')。
就个人而言,在编写EF Linq表达式时,我的查询代码将始终检查字符串上的IsNullOrEmpty,而不附加未提供实际条件的.Where()
条件。这样,WHERE子句仅适用于提供的条件。
即如果我相信数据库不会区分大小写:
if(!string.IsNullOrEmpty(substring))
query = query.Where(entity => entity.Tracking_Number.Contains(substring));
如果我担心数据库可能区分大小写:
if(!string.IsNullOrEmpty(substring))
query = query.Where( entity => entity.Tracking_Number.ToLower().Contains(substring.ToLower()));
即使数据库仅用于此应用程序,我也希望设置一个标准,即Tracking_Number始终以小写形式存储。实体属性将强制所有设置值均小写。 (无需在查询中使用.Tracking_Number.ToLower()。)