2013-07-18 3 views
1

Предположим, что в качестве объекта критериев используется массив Type, который указывает дочерние типы, которые должны быть показаны.Фильтр IQueryable для массива типов

Модели:

public abstract class Shape { } 

public class Circle : Shape { } 

public class Rectangle : Shape { } 

Я реализовал метод расширения, которые применяются такой запрос

public static IQueryable<TSource> OfTypes<TSource, TResult>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, TResult>> expression, 
    params Type[] types) 
{ 
    if (!types.Any()) 
    { 
     return source; 
    } 

    Expression finalExpression = Expression.TypeIs(expression, types.First()); 

    foreach (var type in types.Skip(1)) 
    { 
     finalExpression = Expression.OrElse(
      Expression.TypeIs(expression, type), 
      finalExpression); 
    } 

    var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(
     finalExpression, 
     expression.Parameters); 

    return source.Where(lambdaExpression); 
} 

Тогда я могу использовать его как этот

var types = new Type[] { typeof(Circle), typeof(Rectange) }; 
db.Shapres.OfTypes(s => s, types); 

Сформированный выражение что-то подобные

e => e is Circle || e is Rectange 

Именно то, что я хочу, но я получаю эту ошибку

Тип выражения узел LINQ «Lambda» не поддерживается в LINQ к Entities.

Даже я использовал AsExpandable() метод LinqKit в последней строке метода расширения:

return source.AsExpandable().Where(lambdaExpression); 

Но опять та же ошибка.

Я также попытался PredicateBuilder, как это, но опять та же ошибка

var finalExpression = PredicateBuilder.False<TSource>(); 

foreach (var type in types) 
{ 
    var expressionParameter = Expression.Parameter(typeof(TSource), "it"); 
    var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(
     Expression.TypeIs(expression, type), 
     expressionParameter); 
    finalExpression.Or(lambdaExpression); 
} 

В чем проблема?

Как можно преобразовать Expression в Expression<Func<T, TResult>> в EF без проблем?

Или как передать пример Expression на метод расширения Where?

Или как я могу использовать Expression.TypeIs для EF?

+0

'если (types.Any (!))' Может вызвать 'NullReferenceException'. – Steve

+0

@Steve - это не моя проблема. –

+0

Я знаю, просто указывая на это. – Steve

ответ

1

Вам необходимо передать параметр функции Лямбда, вы передаете ему выражение, которое было передано, которое является лямбдой. Попробуйте создать параметр внутри метода расширения, удалив аргумент 'expression', поскольку он не нужен.

public static IQueryable<TSource> OfTypes<TSource>(
     this IQueryable<TSource> source, 
     params Type[] types) 
    { 
     if (!types.Any()) 
     { 
      return source; 
     } 

     var param = Expression.Parameter(typeof(TSource), "p"); 

     Expression finalExpression = Expression.TypeIs(param, types.First()); 

     foreach (var type in types.Skip(1)) 
     { 
      finalExpression = Expression.OrElse(
       Expression.TypeIs(param, type), 
       finalExpression); 
     } 

     var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(
      finalExpression, param); 


     return source.Where(lambdaExpression); 
    } 

называется так:

var types = new Type[] { typeof(Circle), typeof(Rectangle) }; 
var test = context.Shapes.OfTypes(types); 
+0

Он работает правильно, но что, если я хотел использовать выражение, чтобы указать свойство, на которое применяется фильтр? Например, 'db.Shapes.OfTypes (s => s.SomeProperty, types);'. Я имею в виду, это невозможно? –

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