Linq& String.ToLower()奇怪的行为

时间:2010-10-20 02:42:45

标签: c# linq string wcf-ria-services


我在服务器端有一个查询,它从邮政编码表中返回不同城市的列表 我正在使用WCF RIA服务 以下查询在provincename == ""

时成功返回228个城市
    public IQueryable<CityPM> 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<CityPM> 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 });
    }

为什么查询不返回任何内容?

3 个答案:

答案 0 :(得分:7)

尝试使用数据库管理工具检查生成的SQL,或者在查询表达式的末尾调用.ToTraceString()。

参考:http://blog.aggregatedintelligence.com/2010/06/viewing-entity-framework-generated-sql.html

我们在使用扩展名时使用ToTraceString:

public static IQueryable<T> TraceSql<T>(this IQueryable<T> 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<CityPM> 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();
}

请原谅我有任何错别字,这是来自记忆。希望它能帮助您理解您的问题。

答案 1 :(得分:4)

解释

我遇到了同样的问题,我发现了为什么会这样。运行SQL事件探查器我发现从 LINQ to 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<CityPM> 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 '%%',否则它将呈现为{{ 1}}。如果传入null,它也会有所帮助。

答案 2 :(得分:0)

这对我有用,如果你喜欢的话试一试

context.MyEntities.Where(p =&gt; p.Email.ToUpper()。Equals(muser.Email.ToUpper()));

注意:我正在查询Oracle