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

Yeo*_*nho 4 c# linq string wcf-ria-services


我在服务器端有一个查询,它从一个zipcode表返回一个不同城市的列表.
我正在使用WCF RIA服务.
以下查询成功返回228个城市provincename == ""

    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 });
    }
Run Code Online (Sandbox Code Playgroud)

但如果我使用如下的ToLower()方法,则查询返回0个城市provincename == "".

    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 });
    }
Run Code Online (Sandbox Code Playgroud)

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

Wil*_*ill 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;
}
Run Code Online (Sandbox Code Playgroud)

然后可以使用如下:

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();
}
Run Code Online (Sandbox Code Playgroud)

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


Bil*_*Kee 6

说明

我遇到了同样的问题,我发现了为什么会发生这种情况。运行 SQL Profiler 我看到从LINQ to SQL生成的WHERE语句在每种情况下都非常不同。

.Where(z => z.Province.Contains(provinceName))
Run Code Online (Sandbox Code Playgroud)

将在 SQL 中呈现为:

WHERE [Province] LIKE N'%%'
Run Code Online (Sandbox Code Playgroud)

正如您所经历的,LIKE '%%'将匹配任何非空结果。

.
然而,

.Where(z => z.Province.ToLower().Contains(provinceName.ToLower()))
Run Code Online (Sandbox Code Playgroud)

将在 SQL 中呈现为:

WHERE ( CAST( CHARINDEX(LOWER(N''), LOWER([Province])) AS int)) > 0
Run Code Online (Sandbox Code Playgroud)

这与LIKE '%%'. SQL 本质上是查看string.Empty字符串Province中的字符。CHARINDEX空字符串的结果为 0,这就是没有返回结果的原因。

.

解决方法

这有点骇人听闻,但它会起作用。仅.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 });
}
Run Code Online (Sandbox Code Playgroud)

通过像这样构造您的代码,LINQ to SQL将呈现为LIKE '%%'好像ProvinceName是一个空字符串,否则它将呈现为CHARINDEX. 如果传入空值,它也有帮助。