簡體   English   中英

查詢實體框架的通用方法

[英]Generic method for querying Entity Framework

我想有一個通用方法通過IEnumerable<TEnum>過濾實體框架IQueryable<TItem> IEnumerable<TEnum> 它的簽名應該看起來像這樣:

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

但是方法內部應該是什么? 如何將Expression<Func<TItem, IEnumerable<TEnum>, bool>>Expression<Func<TItem, bool>>以用作“ 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)));
}

像這樣的電話:

requests = ApplyFilter(requests, states, r => r.State);

當我執行Sharped的答案時,我發現實際上可以完全按照我的意願做。 關鍵是要使用從ExpressionVisitor繼承的自定義類。 此類會將表達式樹中IEnumerable<TEnum>參數的每次出現替換為其實際值。 我的最終代碼:

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

我正在像這樣使用它:

var requests = this.ServiceManager.Messaging.GetRequests();
var states = new[] {RequestState.Active};
requests = ApplyFilter(requests, states, (i, e) => e.Contains(i.State));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM