如何在 LINQ 查询表达式中有条件地添加谓词条件

How to conditionally add predicate conditions in a LINQ query expression

下面的linq逻辑有2个possible基于参数值的表达式,我正在寻找一种方法将这两个表达式组合成一个表达式,主要是为了我可以一次声明和管理连接条件,而不是在 2 个地方。

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();
}