如何在 LINQ 查询表达式中有条件地添加谓词条件
How to conditionally add predicate conditions in a LINQ query expression
下面的linq逻辑有2个possible基于参数值的表达式,我正在寻找一种方法将这两个表达式组合成一个表达式,主要是为了我可以一次声明和管理连接条件,而不是在 2 个地方。
- 第一种情况:根据项目 ID 和如果 parentId 为 null
加入用户和评论 table
- 第二种情况:根据项目id加入用户和评论table并且父id不为空
public Comment GetComments(int projectId, int parentId)
{
List<Comment> comments= new List<Comment>();
if(parentId==null)
{
comments = (from c in context.Comments
join users in context.Users
on c.CreatedBy equals users.Id
where c.ProjectId==projectId && c.ParentId==null
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
else
{
comments = (from c in context.Comments
join users in context.Users
on c.CreatedBy equals users.Id
where c.ProjectId==projectId && ParentId==c.parentId
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
return comments;
}
在有条件逻辑的情况下,与此类似,我们应该组合 多个步骤的查询。没有必要尝试构建一个单一的庞然大物查询,我们也根本不需要使用查询语法...
第一个观察结果是,我们可以在 之前 连接语句应用过滤器,特别是在这种情况下,因为过滤器仅适用于主体 table 并且不受影响通过加入。
对于此特定查询,如果 parentId
设为 nullable,则根本不需要两个单独的查询。那么第二条路径其实满足BOTH个场景:
If parentId
is null
, then we still want to match on ParentId==c.parentId
public List<Comment> GetComments(int projectId, int? parentId)
{
return (from c in context.Comments
join users in context.Users on c.CreatedBy equals users.Id
where c.ProjectId==projectId && c.ParentId==parentId
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
如果您不能使 parentId
可为空,那么大概我们使用 0 或更少来指示 first 路径,而不是 null。在那种情况下,如果您有多个 conditional 组条件,我发现首先使用 fluent 准备初始查询会更容易,然后您如果您觉得需要,可以使用 query 语法结束:
public List<Comment> GetComments(int projectId, int parentId)
{
var commentsQuery = context.Comments.Where(c => c.ProjectId == projectId);
if (parentId > 0)
commentsQuery = commentsQuery.Where(c => c.ParentId == parentId);
return (from c in commentsQuery
join users in context.Users on c.CreatedBy equals users.Id
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
下面的linq逻辑有2个possible基于参数值的表达式,我正在寻找一种方法将这两个表达式组合成一个表达式,主要是为了我可以一次声明和管理连接条件,而不是在 2 个地方。
- 第一种情况:根据项目 ID 和如果 parentId 为 null 加入用户和评论 table
- 第二种情况:根据项目id加入用户和评论table并且父id不为空
public Comment GetComments(int projectId, int parentId)
{
List<Comment> comments= new List<Comment>();
if(parentId==null)
{
comments = (from c in context.Comments
join users in context.Users
on c.CreatedBy equals users.Id
where c.ProjectId==projectId && c.ParentId==null
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
else
{
comments = (from c in context.Comments
join users in context.Users
on c.CreatedBy equals users.Id
where c.ProjectId==projectId && ParentId==c.parentId
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
return comments;
}
在有条件逻辑的情况下,与此类似,我们应该组合 多个步骤的查询。没有必要尝试构建一个单一的庞然大物查询,我们也根本不需要使用查询语法...
第一个观察结果是,我们可以在 之前 连接语句应用过滤器,特别是在这种情况下,因为过滤器仅适用于主体 table 并且不受影响通过加入。
对于此特定查询,如果 parentId
设为 nullable,则根本不需要两个单独的查询。那么第二条路径其实满足BOTH个场景:
If
parentId
isnull
, then we still want to match on ParentId==c.parentId
public List<Comment> GetComments(int projectId, int? parentId)
{
return (from c in context.Comments
join users in context.Users on c.CreatedBy equals users.Id
where c.ProjectId==projectId && c.ParentId==parentId
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}
如果您不能使 parentId
可为空,那么大概我们使用 0 或更少来指示 first 路径,而不是 null。在那种情况下,如果您有多个 conditional 组条件,我发现首先使用 fluent 准备初始查询会更容易,然后您如果您觉得需要,可以使用 query 语法结束:
public List<Comment> GetComments(int projectId, int parentId)
{
var commentsQuery = context.Comments.Where(c => c.ProjectId == projectId);
if (parentId > 0)
commentsQuery = commentsQuery.Where(c => c.ParentId == parentId);
return (from c in commentsQuery
join users in context.Users on c.CreatedBy equals users.Id
select new CommentModel
{
Id = c.Id,
Message = c.Message,
Date = c.Date,
UserName = users.UserName,
ProjectId=projectId,
}).ToList();
}