【问题标题】:How to implement SkipWhile with Linq to Sql without first loading the whole list into memory?如何在不先将整个列表加载到内存的情况下使用 Linq to Sql 实现 SkipWhile?
【发布时间】:2012-03-02 22:12:11
【问题描述】:

我需要将存储在数据库中的文章按发布日期降序排列,然后使用Id == 100 获取文章后面的前 20 条记录。

这就是我想用 Linq 做的事情:

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

但是,这会生成 NotSupportedException,因为在 Linq to Sql 中不支持 SkipWhile(请参阅 here)。

一种可能的解决方案是执行查询,然后使用 Linq 将 SkipWhile 应用于 Object:

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

但这意味着我需要先将整个有序列表加载到内存中,然后在带有Id == 100 的文章之后取 20 篇文章。

有没有办法避免这种巨大的内存消耗?

更一般地说,在 SQL 中实现这一目标的最佳方法是什么?

【问题讨论】:

  • 有趣的要求。 IdPublicationDate 之间有什么关系吗?你真的想做的是按日期订购它们,沿着那个列表直到你到达Id100,然后然后拿下接下来的20个?
  • 是的,这正是我想要的。 IdPublicationDate 之间没有关系。这个要求的原因是我需要获取在我只知道Id的指定文章之后发布的一定数量的文章。当然,如果我知道那篇文章的PublicationDate,那就容易多了。

标签: c# sql linq linq-to-sql linq-to-objects


【解决方案1】:

添加where语句不是解决方案吗?

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

【讨论】:

  • 是的,我也是这么想的,但是看看实际要求:按日期排序,按照这个列表直到 id 100,然后接下来的 20 个。很奇怪。
  • 如果文章 5 发表在文章 10 之后 (例如由于处于草稿状态),这将不起作用
  • 是的,我误解了这个问题。
【解决方案2】:

如果正如我从列名中猜测的那样,PublicationDate 没有改变,您可以在两个单独的查询中执行此操作:

  • Id == 100 建立ArticlePublicationDate
  • 检索从该日期起的 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);

但这可能对它来说太复杂了。试试看。

【讨论】:

  • 我认为这是一个很好的解决方案(也由@Atzoya 发布),它也可以移动到数据库中的存储过程中。我想我们不能用一个 SQL 查询来做到这一点。这里唯一的问题是在(不太可能的)事件中,我们同时发布了许多具有不同 ID 的文章。但是为了解决这个问题,我们需要在获取文章时就额外的排序规则达成一致,例如通过降序 Ids:var articles = db.Articles .Where(a =&gt; a.PublicationDate &lt;= thresholdDate &amp;&amp; a.Id &lt; 100) .OrderByDescending(a =&gt; a.PublicationDate).ThenByDescending(a =&gt; a.Id) .Take(20);
  • 我试过了,效果很好。 LINQ to SQL 甚至设法将整个 LINQ 查询转换为单个 SQL 查询。
  • 我可以建议您将 Single(a => a.Id == 100) 替换为 Single(aa => aa.Id == 100) 以接受此答案吗?
【解决方案3】:

你可以这样试试

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);

【讨论】:

  • +1 因为这与 AakashM 发布的解决方案相同,但另一个有更清晰的解释
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多