2017-02-17 3 views
0

У меня есть класс DropdownFilter, который имеет:Как передать Func классу, который инкапсулирует выражение на основе этого Func?

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 'Invoke' не поддерживается в 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, чтобы перевести «вызов этого произвольного метода, который у меня есть в коде C#», в SQL. Как вы ожидаете этого? Он не знает, что такое этот метод, что он делает или что SQL может быть эквивалентен ему. – Servy

+0

Вот почему я хочу преобразовать его в выражение. Почему бы мне не сделать это? Если я могу передать выражение извне, почему бы мне не создать выражение внутри, а извне только передать его часть (свойство)? Это вопрос, который я опубликовал. –

+0

Как бы вы это сделали? Как вы могли бы преобразовать некоторую произвольную функцию C# в SQL? Если вы передаете выражение извне, то вы не конвертируете какой-либо произвольный метод C# в SQL, вы конвертируете выражение 'Expression' в 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 функция не строго необходима, но использовать его делает Entity Framework генерировать параметризованное выражение.

Смежные вопросы