LINQ:仅当值不为null时才添加where子句

Hen*_*nry 22 c# linq asp.net performance sql-server-2008

我知道一种典型的方式是这样的:

IQueryable query = from staff in dataContext.Staffs;
if(name1 != null)
{
     query = from staff in query where (staff.name == name1);
}
Run Code Online (Sandbox Code Playgroud)

但是,从我们从其他开发人员手中接过的程序中,我们看到了这样的代码:

IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 == null || staff.name == name1);
Run Code Online (Sandbox Code Playgroud)

如果这是一个普通的SQL语句,我肯定会说第二个是不好的做法.因为当name1为null时,它会向查询添加无意义的where子句.

但我是LINQ的新手,所以我不确定LINQ是否有所不同?

Muh*_*hid 18

你可以这样写

IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 != null && staff.name == name1);
Run Code Online (Sandbox Code Playgroud)

这样,如果您的第一个条件评估为false,则不会评估条件的第二部分

更新:
如果你写

IQueryable query = from staff in dataContext.Staffs;
    query = from staff in query where (name1 == null || staff.name == name1);
Run Code Online (Sandbox Code Playgroud)

并且name1为null您的条件的第二部分将不会被评估,因为或条件只需要一个条件返回true

请参阅此链接以获取更多详细信息

  • 如果name1为null,则他希望返回所有的Staffs记录:在这种情况下,您的重写将不返回任何内容。 (2认同)

Car*_*000 11

通常这种事情使用流畅的语法而不是查询语法来编写更平滑.

例如

IQueryable query = dataContext.Staffs;
if(name1 != null)
{
     query = query.Where(x => x.name == name1);
}
Run Code Online (Sandbox Code Playgroud)

所以如果name1为null,你就不做任何Where()调用.如果您有多个不同的过滤器,所有这些过滤器可能需要或可能不需要,也许各种不同的排序顺序,我发现这变得更易于管理.

编辑alex:好的,我正在回答有关仅在值不为null时添加where子句的问题.在回答问题的其他部分时,我尝试使用Entity Framework 4来查看LINQ生成的SQL.你通过转换和调用query来做到这一点.结果是该条款如下:ObjectQuery.ToTraceString()WHERE

WHERE @p__linq__0 IS NULL OR [Extent1].[name] = @p__linq__1
Run Code Online (Sandbox Code Playgroud)

所以,是的,它是经典的错误SQL,如果name列上有索引,不要指望它被使用.

编辑#2:使用LINQ to SQL而不是实体框架再次尝试这一点,结果却截然不同.这一次,尝试查询name1为null会导致根本没有任何WHERE条款,正如您所希望的那样; 尝试将其name1作为"a"导致一个简单的WHERE [t0].[name] = @p0@p0发送为"a".实体框架似乎没有优化.这有点令人担忧.

  • 这似乎并没有回答这个问题. (3认同)

Sot*_*oto 5

最好的方法是创建一个扩展方法,该方法将接受条件语句和where表达式。如果条件为true,则它将使用where表达式,否则将不使用它。这可以极大地清理您的代码,而无需if语句。

public static class LinqExtensions
{
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> whereClause)
    {
        if (condition)
        {
            return query.Where(whereClause);
        }
        return query;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样编写代码:

IQueryable<Staffs> query = dataContext.Staffs.AsQueryable().WhereIf(name1 != null, x => x.Name == name1);
Run Code Online (Sandbox Code Playgroud)