C# 查询实体框架的通用方法

C# 查询实体框架的通用方法,c#,entity-framework,generics,C#,Entity Framework,Generics,我想通过IEnumerable获得过滤实体框架IQueryable的通用方法。其签名可能如下所示: public static IQueryable<TItem> ApplyFilter<TItem, TEnum>(IQueryable<TItem> items, IEnumerable<TEnum> enumValues, Expression<Func<TItem, IEnumerable<TEnum>, bool>

我想通过
IEnumerable
获得过滤实体框架
IQueryable
的通用方法。其签名可能如下所示:

public static IQueryable<TItem> ApplyFilter<TItem, TEnum>(IQueryable<TItem> items, IEnumerable<TEnum> enumValues, Expression<Func<TItem, IEnumerable<TEnum>, bool>> predicate)
{
     return items.Where(??????);
}
IQueryable<Request> requests = service.GetAllRequests();
IEnumerable<RequestState> states = new RequestState[] {RequestState.Active, RequestState.Closed};
Expression<Func<Request, IEnumerable<RequestState>, bool>> predicate = (r, s) => s.Contains(r.State);
requests = ApplyFilter(requests, states, predicate);
公共静态IQueryable ApplyFilter(IQueryable项、IEnumerable枚举值、表达式谓词)
{
退货项目。其中(???);
}
我想可以这样称呼它:

public static IQueryable<TItem> ApplyFilter<TItem, TEnum>(IQueryable<TItem> items, IEnumerable<TEnum> enumValues, Expression<Func<TItem, IEnumerable<TEnum>, bool>> predicate)
{
     return items.Where(??????);
}
IQueryable<Request> requests = service.GetAllRequests();
IEnumerable<RequestState> states = new RequestState[] {RequestState.Active, RequestState.Closed};
Expression<Func<Request, IEnumerable<RequestState>, bool>> predicate = (r, s) => s.Contains(r.State);
requests = ApplyFilter(requests, states, predicate);
IQueryable requests=service.GetAllRequests();
IEnumerable states=new RequestState[]{RequestState.Active,RequestState.Closed};
表达式谓词=(r,s)=>s.Contains(r.State);
请求=ApplyFilter(请求、状态、谓词);

但在方法的体内应该是什么呢?如何将
Expression
转换为
Expression
,用作“Where”方法的参数?它能与实体框架一起工作吗?

IMO,谓词应该在您的
ApplyFilter
方法中(关注点方面)。 一种可能的编码方法是:

public static IQueryable<TItem> ApplyFilter<TItem, TEnum>(IQueryable<TItem> items, 
              IEnumerable<TEnum> enumValues, Expression<Func<TItem,TEnum>> enumField)
{
     return items.Where(i => enumValues.Contains(enumField(i)));
}

当我实现夏普的答案时,我发现其实完全可以做我想要做的事情。关键是要使用从ExpressionVisitor继承的自定义类。此类将用表达式树中出现的
IEnumerable
参数的实际值替换该参数。我的最终代码:

public static IQueryable<TFilteredItem> ApplyFilter<TFilteredItem, TEnum>(IQueryable<TFilteredItem> items, IEnumerable<TEnum> enumValues, Expression<Func<TFilteredItem, IEnumerable<TEnum>, bool>> predicate)
{
    ParameterExpression itemParam = predicate.Parameters[0];
    ParameterExpression enumsParam = predicate.Parameters[1];
    var em = new ExpressionModifier<IEnumerable<TEnum>>(enumsParam.Name, enumValues);
    Expression predicateBody = em.Modify(predicate.Body);
    return items.Where(Expression.Lambda<Func<TFilteredItem, bool>>(predicateBody, new[] { itemParam }));
}

public class ExpressionModifier<T> : ExpressionVisitor
{
    private readonly string parameterName;
    private readonly T newValue;
    public Expression Modify(Expression expression)
    {
        return Visit(expression);
    }

    public ExpressionModifier(string parameterName, T newValue)
    {
        this.parameterName = parameterName;
        this.newValue = newValue;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node.Name == this.parameterName ? Expression.Constant(this.newValue, node.Type) : base.VisitParameter(node);
    }
}

是的,这可能是我将使用的解决方案。我只是希望得到更一般的东西,即不局限于“Contains”方法。谢谢你的回答。