Как использовать пользовательское свойство в запросе 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, упомянутый в этот ответ.