在Linq.Table.Where()中使用可选的OR子句

时间:2009-10-26 17:57:24

标签: c# asp.net linq-to-sql lambda

有没有办法让ProjectID检查下面是可选块的一部分?我是最近从Java EE转换的.Net转换器,我正在寻找类似于Hibernate Criteria API的东西。我想简化下面的块,只需要调用Where()一次。我也不确定使用lambdas做Where()的性能影响,因为我刚刚在一周前开始使用.Net。

public IQueryable<Project> FindByIdOrDescription(string search)
    {
        int projectID;
        bool isID = int.TryParse(search, out projectID);

        IQueryable<Project> projects;

        if (isID)
        {
            projects = dataContext.Projects.Where(p => p.ProjectDescription.Contains(search) || p.ProjectID == projectID);
        }
        else
        {
            projects = dataContext.Projects.Where(p => p.ProjectDescription.Contains(search));
        }

        return projects;
    }

3 个答案:

答案 0 :(得分:3)

如果您正在寻找可选择添加AND xyz的内容,则可以直接链接Where次来电话:

var projects = dataContext.Projects.Where(p => p.ProjectDescription.Contains(search));
if (isID)
    projects = projects.Where(p => p.ProjectID == projectID);

不幸的是,当您想要OR xyz时,事情并不那么容易。为此,您需要手动构建谓词表达式。 它不漂亮。一种方法是

Expression<Func<Project, bool>> predicate = p => p.ProjectDescription.Contains(search);
if (isID)
{
    ParameterExpression param = expr.Body.Parameters[0];
    predicate = Expression.Lambda<Func<Project, bool>>(
        Expression.Or(
            expr.Body,
            Expression.Equal(
                Expression.Property(param, "ProjectID"),
                Expression.Constant(projectID))),
        param);
}
var projects = dataContext.Projects.Where(predicate);

请注意,向现有谓词添加条件比创建初始表达式要多得多,因为我们需要完全重建表达式。 (谓词必须始终使用单个参数;使用lambda语法声明两个表达式将创建两个单独的参数表达式对象,每个谓词一个。)请注意,当您使用lambda语法初始化时,C#编译器在幕后大致相同谓词。

请注意,如果您习惯使用Hibernate的标准API,这可能看起来很熟悉,只是更详细一点。


但请注意,某些LINQ实现非常智能,因此以下内容也可以使用:

var projects = dataContext.Projects.Where(
    p => p.ProjectDescription.Contains(search)
      || (isID && p.ProjectID == projectID));
但是,

YMMV,请检查生成的SQL。

答案 1 :(得分:1)

在第一次实际访问IQueryable的元素之前,不会解析和执行查询。因此,无论你多少在哪里追加(你甚至不在这里做),你不必担心多次击中数据库。

答案 2 :(得分:0)

委托/表达式可以“链接”,就像这样(未经测试的伪代码):

Expression<Predicate<Project>> predicate = p => p.ProjectDescription.Contains(search);
if ( isID ) 
    predicate = p => predicate(p) || p.ProjectID == projectId;

return dataContext.Where(predicate);