.net 基于过滤对象的EF查询自动过滤

8hhllhi2  于 2023-01-22  发布在  .NET
关注(0)|答案(1)|浏览(95)

假设我们有以下类:

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

我自己尝试过几次,但是失败了。从我的Angular 来看,主要的问题是我不能指定返回不同类型的表达式的列表,所以每次都以一些可怕的、巨大的和不可读的反射结束。所以也许我错过了一些明显的方法来做到这一点,或者已经有了解决方案-任何东西都可以工作,除非它不是一英里的不可读的代码。只是不希望治疗比疾病更糟糕。
先谢了

iezvtpos

iezvtpos1#

您可以做的一件事是引入扩展方法,以便检查可以变成一个liners/chained(实际的方法名称由您决定):

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, IEnumerable<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中,使用source generators可能是比反射更可取的方法。

相关问题