实体框架投影转换失败GroupBy



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

使用LINQPAD7中的演示数据库,这里有一个原始查询的例子,以及我如何尝试优化它

作品:

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

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

更改此项:

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到sql,这将非常有效。

最新更新