簡體   English   中英

轉換表達式 <T, string> &gt;表達 <T, bool> &gt;

[英]Convert Expression<T, string>> to Expression<T, bool>>

因此我想根據一些簡單的設置自動進行過濾。 我的代碼是這樣的:

public ActionResult Index() // here I want to add filtering for Status I only want to show the active ones
{
    IQueryable<Ticket> cases = db.Cases().AsQueryable();
    cases = cases.EnablePaging().EnableFilterFor(x => x.Status);
    return View(cases);
}

EnableFilterFor如下所示:

public static IQueryable<T> EnableFilterFor<T>(this IQueryable<T> queryable, Expression<Func<T, string>> keySelector)
{ 
    string filterValue= "Active";
    //Expression<Func<T, bool>> whereexpresion = keySelector.Compile() == "Active"

    queryable = queryable.Where(
       //here do the magic !! so that the result will be 'x=>x.Status == filterValue');
    );
    return queryable;
}

我在Google上搜索了很多,嘗試了許多不同的方法,但沒有成功。 我必須以某種方式組合keySelector和filterValue才能工作(我需要一個Expression來使Where方法起作用)。 任何幫助將不勝感激。

編輯:在測試了兩種解決方案之后(謝謝你們!),我發現Poke具有最好的解決方案。 戳他的代碼是唯一不會更改SQL生成方式的代碼。 當我看一下Servy他生成的SQL時,總是會執行EXTRA Sql選擇查詢和EXTRA並在WHERE子句中……不知道為什么:)

IQueryable.Where需要Expression<Func<T, bool>> ,因此這就是我們需要構建的東西。 當我們要集成另一個表達式( Expression<Func<T, string>> )中的內容時,我們必須“手動”構建表達式。

因此,最后,我們要調用LambdaExpression.Lambda<Func<T, bool>>(…)以獲取Where的表達式,但我們需要填寫表達式主體:

// first, we reuse the parameter from the `keySelector` expression
ParameterExpression param = keySelector.Parameters[0];

// The body is now just an equality comparison of the `keySelector`
// body, and the constant `filterValue`
Expression body = Expression.Equal(keySelector.Body, Expression.Constant(filterValue));

// now we just need to create a lambda expression for that body with the
// saved parameter and it’s all done:
queryable = queryable.Where(Expression.Lambda<Func<T, bool>>(body, param));

我們這里需要一個用於表達式的Compose方法。 它將使用一個使用值的表達式,以及在概念上將第一個表達式的結果用作其輸入的另一個表達式,生成一個新的輸出。

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

它將需要具有將一個表達式替換為另一個表達式的能力,我們可以使用以下方法做到這一點:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

現在我們可以寫:

public static IQueryable<T> EnableFilterFor<T>(
    this IQueryable<T> queryable, 
    Expression<Func<T, string>> keySelector)
{ 
    string filterValue= "Active";

    return queryable.Where(keySelector.Compose(status => status == filterValue));
}

暫無
暫無

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

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