繁体   English   中英

根据过滤器 object 自动过滤 EF 查询

[英]Filtering EF query based on filter object automatically

假设我们有以下课程:

class A
{
    public int Id {get; set;}
    public string Name {get; set;}
} 

class FilterA
{
    public List<int> Ids {get; set;}
    public List<string> Names {get; set;}
}

我有一个 IQueryable,我需要以某种通用方式根据 FilterA 中提供的值进行过滤,因为在实际项目中我必须处理数百个这样的对象,每个对象都有数十个属性,我厌倦了写意大利面条代码如下:

if(filter.Ids.Any())
{
    query = query.Where(q=>filter.Ids.Contains(q.Id));
}

if(filter.Names.Any())
{
    query = query.Where(q=>filter.Names.Contains(q.Name));
}  
...

我试图自己实现几次,但都失败了。 从我的角度来看,主要问题是我无法指定返回不同类型的表达式列表,因此每次都以一些可怕的、巨大的和不可读的反射结束。 因此,也许我遗漏了一些明显的方法,或者已经有了解决方案——除非它不是一大堆不可读的代码,否则一切都会起作用,只是不希望治疗比疾病更糟。

提前致谢

你可以做的一件事是引入扩展方法,这样检查就可以变成一个衬里/链接(实际的方法名称由你决定):

public static class QueryableExts
{
    private static MethodInfo? _methodInfo = typeof(Enumerable).GetMethod(nameof(Enumerable.Contains));

    public static IQueryable<T> WhereInNotNullOrEmpty<T, TKey>(
        this IQueryable<T> q, 
        Expression<Func<T, TKey>> selector, 
        ICollection<TKey>? values)
    {
        if (values == null || values.Any())
        {
            return q;
        }
        var collection = Expression.Constant(values);
        var contains = Expression.Call(_methodInfo, collection, selector.Body);
        var expression = Expression.Lambda<Func<T, bool>>(contains, selector.Parameters);
        return q.Where(expression);
    }
}

和用法:

query = query
    .WhereInNotNullOrEmpty(q => q.Id, filter.Ids)
    .WhereInNotNullOrEmpty(q => q.Name, filter.Names);

除此之外,如果您想以更动态的方式应用此过滤,则只能使用一些代码生成/反射。 我认为使用源生成器可能是比在现代 .NET 中对此进行反射更可取的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM