实体框架投影翻译失败 GroupBy

发布于 2025-01-11 18:30:30 字数 1053 浏览 0 评论 0原文

我一直在清理一些实体 LINQ 方法查询,以尝试优化项目中生成的查询,并试图避免由外部的 GROUP BY 进行的 JOIN钥匙。但实体框架遇到了意外的投影失败。

使用 LINQPAD 7 中的演示数据库,下面是原始查询的示例以及我如何尝试优化它。

有效:

Albums
    .Select(a => a.Tracks.OrderBy(t => t.Milliseconds).First())
    .Select(g => new { g.Name, g.Composer })
    .Dump();

运行时异常:

Tracks.GroupBy(t => t.AlbumId)
    .Select(g => g.OrderBy(t => t.Milliseconds).First())
    .Select(g => new { g.Name, g.Composer })
    .Dump();

现在我知道我可以执行以下操作,但它会生成一个非常奇怪的 SQL 查询(连接到自身),并且不像失败的示例那样清晰易读。

Tracks.GroupBy(t => t.AlbumId)
    .Select(g => g.OrderBy(t => t.Milliseconds).Select(g => new { g.Name, g.Composer }).First())
    .Dump();

谁能解释为什么实体框架不喜欢 GroupBy 后跟选择和投影?虽然与表的类似连接可以正常工作吗?

我正在寻找的最佳查询是:

SELECT Name, Composer
FROM (
    SELECT Name, Composer, ROW_NUMBER() OVER(PARTITION BY AlbumId ORDER BY Milliseconds) AS row
    FROM Track
)
WHERE row <= 1

I've been cleaning up some Entity LINQ Method queries, to try and optimize generated queries in a project, and was attempting to avoid a JOIN, by GROUP BY of a foreign key. But ran into an unexpected projection failure with Entity Framework.

Using the demo database in LINQPAD 7, here's an example of the original query and how I'm attempting to optimize it.

Works:

Albums
    .Select(a => a.Tracks.OrderBy(t => t.Milliseconds).First())
    .Select(g => new { g.Name, g.Composer })
    .Dump();

Runtime Exception:

Tracks.GroupBy(t => t.AlbumId)
    .Select(g => g.OrderBy(t => t.Milliseconds).First())
    .Select(g => new { g.Name, g.Composer })
    .Dump();

Now I understand I can do the following, but it makes a very odd SQL query (that joins to itself) and isn't as clean to read as the failing example.

Tracks.GroupBy(t => t.AlbumId)
    .Select(g => g.OrderBy(t => t.Milliseconds).Select(g => new { g.Name, g.Composer }).First())
    .Dump();

Can anyone explain why Entity Framework doesn't like the GroupBy followed by a selection, and a projection? While a similar join to a table works fine?

The optimal query I'm looking for is:

SELECT Name, Composer
FROM (
    SELECT Name, Composer, ROW_NUMBER() OVER(PARTITION BY AlbumId ORDER BY Milliseconds) AS row
    FROM Track
)
WHERE row <= 1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

百变从容 2025-01-18 18:30:30

我注意到,如果您更改查询顺序,则不会发生异常...

更改此:

Tracks
    .GroupBy(t => t.AlbumId)
    .Select(g => g.OrderBy(t => t.Milliseconds).First())
    .Select(g => new { g.Name, g.Composer })
    .Dump();

这样:

Tracks
    .OrderBy(x => x.Milliseconds)
    .GroupBy(x => x.AlbumId)
    .Select(x => new { 
        x.FirstOrDefault().Name, 
        x.FirstOrDefault().Composer 
    })

我认为这是因为您试图对组内的列表进行排序,而您应该首先对所有结果进行排序然后进行分组,虽然我不完全确定。如果不是 linq to sql,这会工作得很好。

I have noticed that if you change query order, the exception does not occur...

Change this:

Tracks
    .GroupBy(t => t.AlbumId)
    .Select(g => g.OrderBy(t => t.Milliseconds).First())
    .Select(g => new { g.Name, g.Composer })
    .Dump();

With this:

Tracks
    .OrderBy(x => x.Milliseconds)
    .GroupBy(x => x.AlbumId)
    .Select(x => new { 
        x.FirstOrDefault().Name, 
        x.FirstOrDefault().Composer 
    })

I think it's because you're trying to sort lists within groups, when you should be sorting all results first and then grouping, though I'm not entirely sure. This, if it wasn't linq to sql, would work just fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文