LINQ to Entities does not recognize the method
LINQ to Entities does not recognize the method 'Boolean TagsCheck(Library.MVVM.Model.Book)' method, and this method cannot be translated into a store expression
Насколько я понял, эта ошибка появляется потому что выражение в запросе не может преобразоваться в sql запрос. И я не могу понять как мне заменить мою функцию на запрос.
Сам запрос
BookList = db.Books.Include("Tags").Where(b => b.Name.Trim().Contains(BookSearch.Trim()) && TagsCheck(b)).ToList();
И функция
bool TagsCheck(Book book)
{
using (DatabaseContext db = new DatabaseContext())
{
foreach (Tag tag in FilterTagList)
if (!book.Tags.Contains(db.Tags.FirstOrDefault(t => t.TagId == tag.TagId)))
return false;
return true;
}
}
В самом запросе я пытаюсь получить список книг, в список тегов которых, входят теги из списка FilterTagList. Подскажите возможное решение.
Ответы (2 шт):
Если вы корректно описали ту часть кода, которую вы не показали здесь, касательно строения классов Book и Tag, а так-же BookSearch поля, заведены компараторы на подобии TagComparer, то должно быть достаточно:
class TagComparer : IEqualityComparer<Tag>
{
public bool Equals(Tag t1, Tag t2)
{
if (t1 == null && t2 == null) return true;
else if (t1 == null || t2 == null) return false;
else if (t1.TagId == t2.TagId) return true;
else return false;
}
public int GetHashCode(Tag tx)
{
return (tx?.TagId ?? 0).GetHashCode();
}
}
BookList = db.Books
.Include("Tags")
.Where(b
=> b.Name.Contains(BookSearch.Trim())
&& b.Tags.Any(a => FilterTagList.Contains(a, new TagComparer())))
.ToList();
Метод TagsCheck должен возвращать Expression<Func<Book, bool>>, чтобы его можно было использовать в linq-запросах Entity Framework.
Насколько я понял, в этом методе проверяется, содержится ли хоть один тег, назначенный книге, в списке FilterTagList.
Этот код можно записать так:
Expression<Func<Book, bool>> TagsCheck()
{
return book => book.Tags.Any(tag => FilterTagList.Contains(tag));
}
Использовать его следует так:
var books = db.Books.Include("Tags")
.Where(b => b.Name.Trim().Contains(BookSearch.Trim()))
.Where(TagsCheck())
.ToList();
Обратите внимание, его обязательно нужно использовать так: Where(TagsCheck()). Потому что он возвращает Expression! Он не возвращает значение bool!
Его невозможно использовать вот так: .Where(book => TagsCheck()), потому что тогда он конвертируется в делегат.
Он возвращает выражение book => book.Tags.Any(tag => FilterTagList.Contains(tag)) и именно оно будет подставлено в месте вызова.
И, соответственно, такой метод не получится использовать с логическим оператором &&. Отсюда следует отдельный вызов Where.
Метод не принимает параметр, потому что параметр book принимает Expression (выражение). Поэтому, чтобы не возникло соблазна всё-таки попытаться воткнуть какой-нибудь параметр, можно сделать свойство вместо метода:
Expression<Func<Book, bool>> TagsCheck =>
book => book.Tags.Any(tag => FilterTagList.Contains(tag));
Его использование, естественно, будет без круглых скобочек:
.Where(TagsCheck)