当网格属性没有实体属性时,如何基于网格过滤构建LINQ谓词/ dynamic.LINQ查询?

时间:2016-10-06 22:10:52

标签: c# linq dynamic-linq predicatebuilder

我有一个网格传递过滤器。所以我可能有一个像这样的对象:

var filter = new Filter(){
   Member = "Titles",
   Operator = Filter.Operators.IsEqualTo,
   Value = "Developer"
};

然后我需要采取这个并扩展IQueryable以便这样做,我使用dynamic.LINQ并有一个方法来应用这些过滤器:

private IQueryable<TReportClass> ApplyFilter(ReportFilter filter, IQueryable<TReportClass> baseQuery)
    {
        switch (filter.Operator)
        {
            case ReportFilter.Operators.Contains:
                baseQuery = baseQuery.Where(string.Format("{0}.Contains(@0)", filter.Member), filter.Value);
                break;
            case ReportFilter.Operators.DoesNotContain:
                baseQuery = baseQuery.Where(string.Format("!{0}.Contains(@0)", filter.Member), filter.Value);
                break;
            case ReportFilter.Operators.IsEqualTo:
                baseQuery = baseQuery.Where(string.Format("{0} = @0", filter.Member), filter.Value);
                break;
            case ReportFilter.Operators.IsNotEqualTo:
                baseQuery = baseQuery.Where(string.Format("{0} != @0", filter.Member), filter.Value);
                break;
            case ReportFilter.Operators.StartsWith:
                baseQuery = baseQuery.Where(string.Format("{0}.StartsWith(@0)", filter.Member), filter.Value);
                break;
            case ReportFilter.Operators.EndsWith:
                baseQuery = baseQuery.Where(string.Format("{0}.EndsWith(@0)", filter.Member), filter.Value);
                break;
            case ReportFilter.Operators.IsNull:
                baseQuery = baseQuery.Where(string.Format("{0} = NULL", filter.Member));
                break;
            case ReportFilter.Operators.IsNotNull:
                baseQuery = baseQuery.Where(string.Format("{0} != NULL", filter.Member));
                break;
            case ReportFilter.Operators.IsEmpty:
                baseQuery = baseQuery.Where(string.Format("string.IsNullOrEmpty({0})", filter.Member));
                break;
            case ReportFilter.Operators.IsNotEmpty:
                baseQuery = baseQuery.Where(string.Format("!string.IsNullOrEmpty({0})", filter.Member));
                break;
        }

        return baseQuery;
    }

然而,这仅适用于非集合。如何让它与集合一起使用?如果我有这个型号:

public class UserReport : Entity
{
    public string Name { get; set; }
    public string Email { get; set; }
    public List<string> Titles { get; set; }
}

这个查询作为基础:

IQueryable<UserReport> baseQuery = MyDbContext.DbSet<User>.Select(user => new UserReport
        {
            Id = user.Id,
            Name = user.FirstName + " " + user.LastName,
            Email = user.Email,
            Titles = user.Positions.Select(apptment => apptment.Title).ToList()
        })

所以我可以这样打电话:

IQueryable<UserReport> filteredQuery = ApplyFilters(filters, baseQuery);

如何将上述过滤器转换为LINQ,如:

baseQuery.Where(userReport => userReport.Titles.Any(title => title == "Developer")

可以用动态LINQ完成吗?或者我需要构建自己的谓词?如果是这样,我该怎么做?

1 个答案:

答案 0 :(得分:1)

System.Linq.DynamicSystem.Linq.Expressions都可以。

以下是使用System.Linq.Dynamic的解决方案,以使其接近您当前的代码。您所需要的只是确定成员是否是集合并使用以下模式作为动态标准:

收藏: {PropertyName}.Any(it{condition})
对象: {PropertyName}{condition}

实施可能是这样的(基本上用string.Format取代Func<string, string, string>):

private IQueryable<TReportClass> ApplyFilter(ReportFilter filter, IQueryable<TReportClass> baseQuery)
{
    var property = typeof(TReportClass).GetProperty(filterMember);
    bool isCollection = property.Type != typeof(string) &&
        && typeof(IEnumerable).IsAssignableFrom(property.Type);
    Func<string, string, string> condtion;
    if (isCollection)
        condition = (format, member) => string.Format("{0}.Any({1})", member, string.Format(format, "it"));
    else
        condition = (format, member) => string.Format(format, member);
    switch (filter.Operator)
    {
        case ReportFilter.Operators.Contains:
            baseQuery = baseQuery.Where(condition("{0}.Contains(@0)", filter.Member), filter.Value);
            break;
        case ReportFilter.Operators.DoesNotContain:
            baseQuery = baseQuery.Where(condition("!{0}.Contains(@0)", filter.Member), filter.Value);
            break;
        case ReportFilter.Operators.IsEqualTo:
            baseQuery = baseQuery.Where(condition("{0} = @0", filter.Member), filter.Value);
            break;
        case ReportFilter.Operators.IsNotEqualTo:
            baseQuery = baseQuery.Where(condition("{0} != @0", filter.Member), filter.Value);
            break;
        case ReportFilter.Operators.StartsWith:
            baseQuery = baseQuery.Where(condition("{0}.StartsWith(@0)", filter.Member), filter.Value);
            break;
        case ReportFilter.Operators.EndsWith:
            baseQuery = baseQuery.Where(condition("{0}.EndsWith(@0)", filter.Member), filter.Value);
            break;
        case ReportFilter.Operators.IsNull:
            baseQuery = baseQuery.Where(condition("{0} = NULL", filter.Member));
            break;
        case ReportFilter.Operators.IsNotNull:
            baseQuery = baseQuery.Where(condition("{0} != NULL", filter.Member));
            break;
        case ReportFilter.Operators.IsEmpty:
            baseQuery = baseQuery.Where(condition("string.IsNullOrEmpty({0})", filter.Member));
            break;
        case ReportFilter.Operators.IsNotEmpty:
            baseQuery = baseQuery.Where(condition("!string.IsNullOrEmpty({0})", filter.Member));
            break;
    }

    return baseQuery;
}