2013-07-05 3 views
2

Я использую Entity Framework для доступа к моделям домена, все из которых реализуют интерфейс (IPublishable), который указывает свойства, указывающие, был ли элемент опубликован..NET LINQ to Entities base where clause for generic Тип

При доступе к элементам с лицевой стороны я всегда хочу отфильтровать неопубликованные элементы. Таким образом, каждый раз, когда я пишу запрос я делаю что-то похожее на это (где на следующий DbSets Objects1 и Objects2 как реализовать IPublishable

context.Objects1.Where(x => x.IsPublished ...).OrderBy(x => x.Id).ToList() 
context.Objects2.Where(x => x.IsPublished ...).First() 

Что было бы идеальным, если я мог бы придать общее Where() положение во всех моих запросы в пределах моего веб-приложения или если существует способ, чтобы написать метод расширения, который я мог бы включать в каждом запросе.

Я попытался создать метод расширения для всех LINQ запросов

public static IEnumerable<T> FrontEnd<T>(this DbSet<T> dbSet) where T : class { 
    return dbSet.Cast<IPublishable>().Where(x => x.IsPublished ...).Cast<T>(); 
} 

И использовать как т его ...

context.Objects1.FrontEnd().Where(x => ...).OrderBy(... 

Однако я получаю ошибку «LINQ к Entities поддерживает только литье EDM примитивные или перечисления типов»

Я новичок в EF, так что любая информация была бы большая помощь. Thanks

+0

Я бы подумал, что для этого может быть создано какое-то [выражение] (http://msdn.microsoft.com/en-us/library/bb397951.aspx). – Romoku

+0

Чтобы достичь чего-то подобного, я закончил использование динамического linq. Но это было только для определенного подмножества данных, а не «всех запросов linq» по мере необходимости, поэтому я не уверен, что это именно то, что вы ищете. – Mansfield

+0

Я думаю, что истинным ответом, который я искал, был промежуточный промежуток между моей инфраструктурой App и Entity, в которой я мог перехватывать запросы и добавлять на базу, где предложение, которое я использовал во всех своих запросах. – JDandChips

ответ

2

ОБНОВЛЕНО согласно комментариям - это работает

public static IQueryable<T> FrontEnd<T>(this DbSet<T> dbSet) 
    where T : class, IPublishable 
{ 
    return dbSet.Where(x => x.IsPublished); 
} 

и может быть использован, как это:

context.Objects1.FrontEnd().Where(x => ...).OrderBy(... 

Вы можете попробовать любой из этих вариантов:

public static IQueryable<dynamic> FrontEnd(this DbSet<dynamic> dbSet) 
{ 
    return dbSet.Where(x => (x as IPublishable).IsPublished); 
} 

или

public static IQueryable<T> FrontEnd<T>(this DbSet<T> dbSet) 
    where T : class, IPublishable 
{ 
    return dbSet.Where(x => x.IsPublished); 
} 

примечание:

первый вариант использует динамический так медленнее со вторым вариантом вы должны указать тип в вызове интерфейсной() например

context.Objects1.FrontEnd<Objects1>().Where(x => ...).OrderBy(... 
+0

Это превосходно, вы искали! Я внедрил предложение 2 и обнаружил, что мне не нужно указывать '' .. глядя на пример, который вы указали, и мой код, я уверен, что они идентичны? Не то, чтобы я жалуюсь :) – JDandChips

0

Я думаю, что LINQ to Entities не знает, как сопоставить оператор приведения с запросом SQL. В качестве предложения вы можете попробовать что-то вроде этого:

IEnumerable<IPublishable> ReadPublishable(Expression<Func<DomainModelType, bool>> condition) 

Выражение действует как предикат. Таким образом, вы передаете функции ReadPublishable предикат, который фильтрует доступные вам IPublishable объекты. Я пробовал успешно, но только по простым предикатам, поэтому я не знаю, работает ли это, если вы используете операторы «есть» или «как».