Как реализовать SkipWhile с Linq to Sql без предварительной загрузки всего списка в память? - PullRequest
12 голосов
/ 10 февраля 2012

Мне нужно упорядочить статьи, хранящиеся в базе данных, по убыванию даты публикации, а затем взять первые 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 to Object:

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

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

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

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

Ответы [ 3 ]

5 голосов
/ 10 февраля 2012

Если, как я догадываюсь из названия столбца, 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);

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

1 голос
/ 10 февраля 2012

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

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);
0 голосов
/ 10 февраля 2012

Разве это не решение просто добавить оператор where?

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