Вы звоните GetCommentsByPostId
в пределах того, что в конечном итоге является деревом выражений. Это дерево, когда оно составлено в BlogService.GetPublicPosts
, преобразуется в SQL.
Во время этого преобразования это просто вызов метода, не более того. Linq to Sql понимает определенные вызовы методов, и вы не один из них. Отсюда и ошибка.
На первый взгляд, это должно сработать. Вы пишете многоразовые запросы и составляете их из других запросов. Однако на самом деле вы говорите: «во время обработки каждой строки на сервере базы данных вызывайте этот метод», чего он явно не может сделать. Тот факт, что он принимает IQueryable<T>
и возвращает IQueryable<T>
, не делает его особенным.
Подумайте об этом так: вы передаете postId
на GetCategoriesByPostId
. Вы не можете вызывать этот метод, пока у вас не будет postId
, и у вас его не будет, пока вы не окажетесь на сервере в запросе.
Возможно, вам потребуется определить общие Expression<>
экземпляры для подзапросов и использовать их в композиции. Я не думал о том, как это будет выглядеть, но это, безусловно, выполнимо.
Edit:
Если вы замените
let categories = GetCategoriesByPostId(p.PostId)
let comments = GetCommentsByPostId(p.PostId)
...
Categories = new LazyList<Category>(categories),
Comments = new LazyList<Comment>(comments),
с
Categories = new LazyList<Category>(GetCategoriesByPostId(p.PostId)),
Comments = new LazyList<Comment>(GetCommentsByPostId(p.PostId)),
запрос больше не будет генерировать исключение.
Это потому, что let
объявляет переменные диапазона, которые находятся в области видимости для каждой строки. Они должны быть рассчитаны на сервере.
Проекции, однако, позволяют вам помещать произвольный код в присваивания, который затем выполняется при построении результатов на клиенте. Это означает, что будут вызваны оба метода, каждый из которых выдаст свой собственный запрос.