如何过滤 IQueryable<T> 的嵌套项?

How can I filter nested items of IQueryable<T>?

我正在构建 Expression<Func<Project, bool>> 类型的表达式,其中 returns 来自数据库的正确 IQueryable<Project>IQueryable<Project> 有一个 SubProjects 的嵌套集合,我也想对其进行过滤。看起来像这样

这可以通过一次调用数据库来完成吗?

例如:

Expression<Func<Project, bool>> projectFilter = FilterEnabled();

projectFilter = projectFilter.And(GetProjectsByOrganization());

var projectData = GetProjectsAsQueryable(projectFilter); //returns correct projects

这就是我想做的事情:

Expression<Func<Project, bool>> projectFilter = FilterEnabled();

projectFilter = projectFilter.And(GetProjectsByOrganization())
                             .And(GetSubProjectsByStartDate());

var projectData = GetProjectsAsQueryable(projectFilter); //returns correct projects and the filtered sub projects by start date

GetProjectsByOrganization如下

public Expression<Func<Project, bool>> GetProjectByOrganization()
{
    var organizationIDs = new List<Guid>();

    if (FilterCriteria.OrganiazaitonId != null)
        organizationIDs = OrganizationRepository.GetParentAndChildrenOrganizationIds(FilterCriteria.OrganiazaitonId.Value).ToList();

    //...

    return prj => FilterCriteria.OrganiazaitonId == null || organizationIDs.Contains(prj.OrganizationID.Value);
}

如何向过滤器添加 Expression<Func<SubProject, bool>>?如果没有,我有什么选择?

您应该能够使用 Expression.AndAlso 将所有 3 个表达式组合成一个新表达式。使用 Expression.PropertyOrField 您可以传递您的子项目而不是您的项目作为参数:

    static Expression<Func<Project, bool>> CombineFilterExpression(
        Expression<Func<Project, bool>> firstProjectFilter, 
        Expression<Func<Project, bool>> secondProjectFilter,
        Expression<Func<SubProject, bool>> subProjectFilter
    )
    {
        //Create Project Parameter
        var param = Expression.Parameter(typeof(Project));
        //Create && Expression
        var body = Expression.AndAlso(
            Expression.Invoke(firstProjectFilter, param),
            Expression.AndAlso( //Create second && Expression
                Expression.Invoke(secondProjectFilter, param),
                //Pass SubProject instead of Project
                Expression.Invoke(subProjectFilter, Expression.PropertyOrField(param, nameof(Project.SubProject)))
            )
        );
        //Make Lambda with Project parameter
        return Expression.Lambda<Func<Project, bool>>(body, param);
    }