Linq&String.ToLower()奇怪的行为
我在服务器端有一个查询,它从一个zipcode表返回一个不同城市的列表。
我正在使用WCF RIA服务。
provincename == ""
时,以下查询成功返回228个城市
public IQueryable GetCities(string provinceName) { return this.ObjectContext.ZipCodes.Where(z => z.Province.Contains(provinceName)) .GroupBy(z => z.City) .Select(g => g.FirstOrDefault()) .Select(zc => new CityPM() { ID = zc.ID, Name = zc.City }); }
但如果我使用如下的ToLower()方法,则当provincename == ""
时,查询返回0个城市。
public IQueryable GetCities(string provinceName) { return this.ObjectContext.ZipCodes.Where(z => z.Province.ToLower().Contains(provinceName.ToLower())) .GroupBy(z => z.City) .Select(g => g.FirstOrDefault()) .Select(zc => new CityPM() { ID = zc.ID, Name = zc.City }); }
为什么查询不返回任何内容?
尝试使用数据库管理工具检查生成的SQL,或者在查询表达式的末尾调用.ToTraceString()。
参考: http : //blog.aggregatedintelligence.com/2010/06/viewing-entity-framework-generated-sql.html
我们在使用扩展时使用ToTraceString:
public static IQueryable TraceSql (this IQueryable query) { var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString(); // do whatever logging of sql you want here, eg (for web) // (view by visiting trace.axd within your site) HttpContext.Current.Trace.Write("sql", sql); return query; }
然后可以使用如下:
public IQueryable GetCities(string provinceName) { return this.ObjectContext.ZipCodes.Where(z => z.Province.ToLower().Contains(provinceName.ToLower())) .GroupBy(z => z.City) .Select(g => g.FirstOrDefault()) .Select(zc => new CityPM() { ID = zc.ID, Name = zc.City }) .TraceSql(); }
请原谅我有任何错别字,这是记忆。 希望它能帮助您理解您的问题。
说明
我遇到了同样的问题,我发现了为什么会这样。 运行SQL事件探查器我发现从LINQ到SQL生成的WHERE语句在每种情况下都是非常不同的。
.Where(z => z.Province.Contains(provinceName))
将在SQL中呈现为:
WHERE [Province] LIKE N'%%'
正如您所经历的那样, LIKE '%%'
将匹配任何非null结果。
。
然而,
.Where(z => z.Province.ToLower().Contains(provinceName.ToLower()))
将在SQL中呈现为:
WHERE ( CAST( CHARINDEX(LOWER(N''), LOWER([Province])) AS int)) > 0
这与LIKE '%%'
非常不同。 SQL本质上是在查看字符串省中的字符串string.Empty
。 CHARINDEX
在空字符串上的结果为0,这就是没有返回结果的原因。
。
解决方法
这有点hackish但它会起作用。 如果字符串不为空,则仅调用.ToLower()
。 以下代码是适合您的一些示例。
public IQueryable GetCities(string provinceName) { var lowerProvinceName = String.IsNullOrEmpty(provinceName) ? string.Empty : provinceName.ToLower(); return this.ObjectContext.ZipCodes.Where(z => z.Province.ToLower().Contains(lowerProvinceName)) .GroupBy(z => z.City) .Select(g => g.FirstOrDefault()) .Select(zc => new CityPM() { ID = zc.ID, Name = zc.City }); }
通过像这样构造你的代码,如果provinceName是一个空字符串, LINQ to SQL将呈现为LIKE '%%'
,否则它将呈现为CHARINDEX
。 如果传入null,它也会有所帮助。
这对我有用,如果你喜欢的话试一试
context.MyEntities.Where(p => p.Email.ToUpper()。Equals(muser.Email.ToUpper()));
注意:我正在查询Oracle