有没有办法让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;
}
答案 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);