【问题标题】:EF Linq to get latest version of row in tableEF Linq 获取表中行的最新版本
【发布时间】:2015-08-21 04:52:23
【问题描述】:

我有一个表格,其中包含有关项目和版本的详细信息,如下所示:

+--------+-----------+------------+----------------------------+
| BookId | VersionId | InstanceId |         TitleText          |
+--------+-----------+------------+----------------------------+
|      1 |         1 |          1 | A great book!              |
|      1 |         2 |          2 | Great Book, v2!            |
|      2 |         1 |          3 | Cooking for Dummies        |
|      3 |         1 |          4 | Networks for Dummies       |
|      2 |         2 |          5 | Cooking for Smarter People |
+--------+-----------+------------+----------------------------+

我正在尝试查询 BookId 的最新(最高)VersionId 的所有行。所以我想要的结果集如下所示:

+--------+-----------+------------+----------------------------+
| BookId | VersionId | InstanceId |         TitleText          |
+--------+-----------+------------+----------------------------+
|      1 |         2 |          2 | Great Book, v2!            |
|      3 |         1 |          4 | Networks for Dummies       |
|      2 |         2 |          5 | Cooking for Smarter People |
+--------+-----------+------------+----------------------------+

我运行的 SQL 是:

select t1.* from Books t1
left outer join Books t2
on (t1.BookId = t2.BookId and t1.VersionId < t2.VersionId)
where t2.BookId is null

但经过一番谷歌搜索后,我无法弄清楚如何将其转换为 linq 查询(使用扩展方法 sytax)。我看到的示例倾向于连接两个不同的表,我只是不知道如何将它塑造成我需要的。

找到了这个,它似乎与我要找的很接近,但是我该怎么做才能让 Foo 和 Bar 成为同一张桌子?

Foo.GroupJoin(
          Bar, 
          foo => foo.Foo_Id,
          bar => bar.Foo_Id,
          (x,y) => new { Foo = x, Bars = y })
    .SelectMany(
          x => x.Bars.DefaultIfEmpty(),
          (x,y) => new { Foo=x.Foo, Bar=y});

【问题讨论】:

    标签: c# linq entity-framework


    【解决方案1】:

    一种方法是将您的反加入转换为不存在的地方:

    select t1.*
    from Books t1
    where not exists (
        select 1
        from Books t2
        where t2.BookId = t1.BookId and t2.VersionId > t1.VersionId
    )
    

    这应该转化为 LINQ:

    AllBooks.Where(t1 => 
        !AllBooks.Any(t2 => t1.BookId == t2.BookId && t2.VersionId > t1.VersionId))
    

    【讨论】:

    • 非常好的解决方案,包括 SQL 和 LINQ。也许这是一个常见的模式,但我以前从未见过它,通常我不得不与嵌套选择和 MAX() 等斗争。未来很高兴知道
    • SQL 绝对是一种常见的模式。我更喜欢@MarcinJuraszek 对 LINQ 的回答,尽管感觉更像是 LINQ-y。
    • 谢谢,这非常适合我克服障碍。
    【解决方案2】:

    改用分组怎么样?

    from x in myTable
    group x by x.BookId into g
    select g.OrderByDescending(y => y.VersionId).FirstOrDefault()
    

    【讨论】:

    • 这当然更简单。 EF真的可以翻译吗?如果是这样,我很好奇它生成的 SQL。
    • 我希望它使用ROW_NUMBER
    • @lc。它会生成这个:pastebin.com/raw.php?i=hRvUg41m 我用 * 替换了选择的列,因为我在公司数据库上运行它 - 但其余的是生成的
    • 现在我正在考虑它 - 这实际上为每个 VersionId 选择 1 行,因此如果有 100 本书和 3 个版本,它将返回 3 行,而不是 100。它应该是 group x by x.BookId 和然后OrderByDescending(g =&gt; g.VersionId)
    • 正确。固定的。谢谢!
    【解决方案3】:

    在 SQL 中,我会结合 JOIN 和 GROUP BY 来查找每本书的最新版本:

    SELECT 
        book.BookId, 
        book.VersionId, 
        book.InstanceId, 
        book.TitleText
    FROM Book AS book
    INNER JOIN (SELECT 
                  book.BookId,
                  MAX(book.VersionId) AS MaxVersion
                FROM Book AS book
                GROUP BY book.BookId) AS grp
      ON book.BookId = grp.BookId AND book.VersionId = grp.MaxVersion
    

    以下 LINQ 查询将被 Entity Framework 翻译成完全相同的:

    from book in Books
    join latest in
        from book in Books
        group book.VersionId by book.BookId into grp
        select new { Id = grp.Key, Version = grp.Max() }
      on new { Id = book.BookId, Version = book.VersionId } equals latest
    select book;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-21
      • 2022-01-27
      相关资源
      最近更新 更多