2017-02-17 34 views
0

我有有DropdownFilter類:如何將Func傳遞給基於該Func封裝Expression的類?

private readonly Func<TEntity, string> fieldWhichMustEqualValue; 

public override IQueryable<TEntity> Filter(IQueryable<TEntity> filteredEntityCollection, string value) 
{ 
    return filteredEntityCollection.Where(entity => this.fieldWhichMustEqualValue(entity) == value); 
} 

我用它作爲:

IQueryable<Invoice> entityCollectionToFilterAndOrder = ... 

var dropdownFilter = new DropdownFilter<Invoice>(invoice => invoice.SomeProperty); 
entityCollectionToFilterAndOrder = dropdownFilter.Filter(entityCollectionToFilterAndOrder, "bla bla bla"); 

這給了我

的LINQ表達式節點類型 '調用' 不是在LINQ支持到 實體。

我明白問題是我基本上要求SQL的等效Invoke,這當然是錯誤的。

我該如何重寫代碼?我知道它必須是一個表達。我的目標是DropDownFilter的使用者只需指定TEntity的屬性,但不提供表達式。即表達式必須封裝到過濾器中。

我曾嘗試:

Expression<Func<TEntity, string>> expr = mc => this.fieldWhichMustEqualValue(mc); 
Expression le = Expression.Equal(expr.Body, Expression.Constant(value)); 
var lambda = Expression.Lambda<Func<TEntity, bool>>(le, expr.Parameters); 
return filteredEntityCollection.Where(lambda); 

,但它基本上給了我同樣的結果。

+1

您正在告訴EF將SQL語句中的「將此C#代碼中的任意方法調用」轉換爲SQL。你期望它如何做到這一點?它無法知道該方法是什麼,它做了什麼,或者什麼SQL可能等同於它。 – Servy

+0

這就是爲什麼我要將其轉換爲表達式。爲什麼我不能做到這一點?如果我可以從外部傳遞表達式,爲什麼我不能在內部創建表達式,並且從外部只傳遞它的一部分(屬性)?這是我發佈的問題。 –

+0

*你會怎麼做?你怎麼可能將一些任意的C#函數轉換爲SQL?如果您從外部傳遞表達式,那麼您不會將任意C#方法轉換爲SQL,而是將表達式轉換爲SQL,並且該表達式包含生成SQL查詢所需的所有信息。 – Servy

回答

0

Func<TEntity, string>是一個C#函數,因此無法在SQL服務器中執行。但是,如果你改變一個表達式,它可以工作:

private readonly Expression<Func<TEntity, string>> fieldWhichMustEqualValue; 

然而,現在Filter功能不會編譯,因爲你不能調用表達式。你需要做的是要組成一個新的表達:

public static UnaryExpression WrapInPropertyAccess(this ConstantExpression constant) { 
    Tuple<object> container = new Tuple<object>(constant.Value); 
    Expression containerExpression = Expression.Constant(container, typeof(Tuple<object>)); 
    MemberExpression propAccess = Expression.Property(containerExpression, "Item1"); 
    UnaryExpression result = Expression.Convert(propAccess, constant.Type); // Cast back the object to the value type 
    return result; 
} 

private Expression<TEntity, bool> FieldEqualsValue(string value) { 
    var comparison = Expression.Equal(fieldWhichMustEqualValue.Body, Expression.Constant(value).WrapInPropertyAccess()); 
    return Expression.Lambda<Func<TEntity, bool>>(comparison, fieldWhichMustEqualValue.Parameters); 
} 

public override IQueryable<TEntity> Filter(IQueryable<TEntity> filteredEntityCollection, string value) 
{ 
    var condition = FieldEqualsValue(value); 
    return filteredEntityCollection.Where(condition); 
} 

並不是必需的WrapInPropertyAccess功能,但使用它使實體框架生成一個參數化表達。

相關問題