Как реализовать SkipWhile с Linq to Sql без предварительной загрузки всего списка в память?

мне нужно заказать статей, хранящихся в базе данных по убыванию даты публикации, а затем взять первые 20 записей после статьи Id == 100.

это то, что я хотел бы сделать с LINQ:

IQueryable<Article> articles = 
    db.Articles
    .OrderByDescending(a => a.PublicationDate)
    .SkipWhile(a => a.Id != 100)
    .Take(20);

однако это создает исключение NotSupportedException, потому что SkipWhile не поддерживается в Linq to Sql (см. здесь).

возможным решением является выполнение запроса, а затем применение SkipWhile использование Linq для Объект:

IEnumerable<ArticleDescriptor> articles = 
    db.Articles
    .OrderByDescending(a => a.PublicationDate)
    .ToList()
    .SkipWhile(a => a.Article.Id != 100)
    .Take(20);

но это означает, мне нужно, чтобы загрузить весь список в памяти, а затем взять 20 статей после Id == 100.

есть ли способ избежать этого огромного потребления памяти?

В общем, каков наилучший способ достичь этого в SQL?

3 ответов


если, как я предполагаю из названия столбца,PublicationDate не изменяется, вы можете сделать это в двух отдельных запросах:

  • установить PublicationDate на Article С Id == 100
  • получить 20 статей с этой даты и далее

что-то типа:

var thresholdDate = db.Articles.Single(a => a.Id == 100).PublicationDate;
var articles = 
    db.Articles
    .Where(a => a.PublicationDate <= thresholdDate)
    .OrderByDescending(a => a.PublicationDate)
    .Take(20);

возможно даже, что LINQ to SQL может перевести это:

var articles = 
    db.Articles
    .Where(a => a.PublicationDate 
             <= db.Articles.Single(aa => aa.Id == 100).PublicationDate)
    .OrderByDescending(a => a.PublicationDate)
    .Take(20);

но это может быть слишком сложным для него. Попробуй и увидишь.


вы можете попробовать так

var articles = 
    db.Articles
    .Where(a => a.PublicationDate < db.Articles
                                    .Where(aa => aa.Id==100)
                                    .Select(aa => aa.PublicationDate)
                                    .SingleOrDefault())
    .OrderByDescending(a => a.PublicationDate)
    .Take(20);

не является ли решение просто добавить оператор where?

IQueryable<Article> articles = db.Articles.Where(a => a.id != 100).OrderByDescending(a => a.PublicationDate).Take(20);