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.EmptyCHARINDEX在空字符串上的结果为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