2014-01-06 2 views
0

Мне нужно разделить предикат над 4-5 разностными сущностями, предпочтительно, без дублирования кода. Все объекты реализуют интерфейс IEntity.Entity Framework Generic Predicate

private Expression<Func<T, bool>> GetUpdatedPredicate<T>(DateTime? lastUpdated) where T : IEntity { 
    if (lastUpdated.HasValue) { 
     return x => (
      x.CreatedAt >= lastUpdated || 
      (x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated) 
     ); 
    } 

    return x => true; 
} 

Затем используется, как это, по множественным множества сущностей:

(
    from s in Db.EntityA.Where(GetUpdatedPredicate<EntityA>(lastUpdated)) 
    where (
     s.User.Id == 1 
    ) 
    select s 
).Future(); 

Но выдает ошибку: Невозможно бросить тип 'EntityA' к типу 'IEntity'. LINQ to Entities поддерживает только листинг примитивных или перечисляемых типов EDM. Есть ли способ сделать это без дублирования кода?

+0

Я думаю, вы пытаетесь сделать что-то похожее на то, что я пытался сделать, и поразить ту же проблему, что и я. Я пытался фильтровать по организации, вы пытаетесь фильтровать User. Посмотрите на решение здесь: http://stackoverflow.com/q/20052827/150342 – Colin

+0

Это действительно работает, но решение @ Moeri ... что ИМО намного приятнее;) – Jamie

ответ

3

Entity Framework имеет проблемы с интерфейсом типа ограничений здесь:

where T : IEntity 

Вы должны добавить дополнительное ограничение, что T должна быть классом:

where T : class, IEntity 

Кроме того, если вы начинаете обнаруживать выражения LINQ, я могу настоятельно рекомендовать библиотеку LinqKit. У этого есть некоторые действительно, действительно отличные вещи.

+0

Вы буквально ответили на вопрос так же, как я закончил писать его с помощью построителя выражений (т.е. .) 'Expression.Parameter (.....)'. Но ваш ответ правильный. Начав обнаруживать выражения LINQ? Я оскорблен;) Но я не наткнулся на LinqKit, но так спасибо :) – Jamie

+1

Эй, эй, я сказал «если» :) Я столкнулся с той же проблемой очень рано, пока я сам обнаруживал выражения, отсюда и мое предположение. LinqKit довольно велик, кстати, вы должны уметь избегать большей части построения выражений вручную с помощью шаблона .Invoke() и .Expand() LinqKit. – Moeri

+1

+1. Я также очень рекомендую linqkit и использовал предикат-строитель во многих угловых случаях, где ничего больше не поместилось бы. не могу сказать достаточно хороших вещей об этом. о, а также, конечно, хороший ответ :-) 'if' –

0

Я предлагаю альтернативный подход.

Во-первых, вместо того, чтобы иметь метод, возвращающий выражение, вы будете иметь частный статический метод, как:

private static bool Evaluate(IEntity x, DateTime? lastUpdated) { 
    if (lastUpdated.HasValue) { 
     return x.CreatedAt >= lastUpdated || 
      (x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated) 
     ); 
    } 

    return true; 
} 

Очевидно, что вы можете назвать упоминание лучше. Затем используйте это нравится:

var result = Db.EntityA.Where(i => i.Evaluate(i, lastUpdated)); 
+2

EF все еще не сможет для преобразования выражения, которое содержит метод .net для sql. – Maarten

0

EF Теперь пытается включить вызов вашего метода в сгенерированном выражение, и это не будет работать. Вы должны исключить метод-вызов из выражения.

Попробуйте создать выражение из своего метода до того, как вы определите свой запрос (нет, я его не тестировал).

DateTime lastUpdated = ...; 
var updatedPredicate = GetUpdatedPredicate<EntityA>(lastUpdated); 
var query = 
(
    from s in Db.EntityA.Where(updatedPredicate) 
    where (
     s.User.Id == 1 
    ) 
    select s 
).Future(); 
+0

К сожалению, это имеет тот же результат: S – Jamie

+0

С ответом @ Moeri вы все равно можете использовать .Where (GetUpdatedPredicate (lastUpdated)) :) – Jamie

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