Как использовать пользовательское свойство в запросе LINQ-to-Entities?
У меня есть класс Post
, который является моделью Entity Framework. Он содержит свойство, подобное этому:
public bool Showable {
get {
return this.Public && this.PublishedDate > DateTime.now
}
}
Я могу использовать его в запросе вроде этого:
from p in db.Posts where p.Showable select p;
но когда у меня есть свойство, которое его использует, например
public IEnumerable<Post> ShowablePosts {
get {
return from p in db.Posts where p.Showable select p;
}
}
то я не могу:
from p in ShowablePosts where p.Id > 42 select p;
В нем говорится:
Указанный член типа 'Showable' не поддерживается в LINQ to Entities. Поддерживаются только инициализаторы, сущности и свойства навигации сущности.
Ответы
Ответ 1
Вы можете сделать это, если вы напишете свойство как Expression
, которое можно перевести на SQL.
Здесь как это сделать.
Это немного сложно, потому что это общее решение сложной проблемы.
Общая идея заключается в следующем: LINQ to Entities (как и все поставщики LINQ) не может переводить скомпилированный код, например ваше свойство, в SQL во время выполнения. LINQ to Objects может выполнять скомпилированный код, но он не может его перевести. Но они могут перевести Expression<T>
. Поэтому вы можете написать:
public static Expression<Func<Post, bool>> WhereActive
{
get
{
return p => p.Public && p.PublishedDate > DateTime.Now;
}
}
Тогда вы могли бы написать:
public IEnumerable<Post> ShowablePosts
{
get
{
return db.Posts.Where(WhereActive);
}
}
... и LINQ to Entities могли бы перевести это. Код в сообщении, который я свяжу, обобщает эту идею.
Ответ 2
К сожалению, Entity Framework просто не поддерживает вычисляемые свойства (то есть свойство, которое возвращает вычисленное значение, а не ссылку на поле поддержки), но он может поддерживаться в будущем.
Ответ 3
Я думаю, что самый простой способ сделать это - использовать атрибут Computed
пакета DelegateDecompiler.EntityFramework
, упомянутый в этот ответ.