实体框架v6组丢失原始排序



我有一个查询的以下部分(它是一个较大查询的末尾-queryBuilder是一个IQueryable

            var results = queryBuilder
                          .OrderBy(x => x.Vehicle.RangeId)
                          .ThenBy(x => x.Rate.Rental)
                          .GroupBy(x => x.Vehicle.RangeId)
                          .Select(x => x.FirstOrDefault())
                          .OrderBy(x => x.Rate.Rental);

它处理的对象具有Vehicle对象和Rental对象。大约有12K辆车,分为大约40个范围(RangeId-Indexed int表示)。

上面的查询运行良好,但并没有达到我的预期。我希望它通过RangeId订购车辆,然后通过租赁(首先是最低租金)。

然后按RangeId对它们进行分组,并从组中选择第一个,这"应该"是最便宜的租金,就像调用groupby之前的命令一样。

然而。事实并非如此。它只是随机地按顺序得到一个。有时它是第二便宜的。有时是第五名,以此类推。出于某种原因,GroupBy没有遵守最初的订单!

我可以通过以下操作来实现这一点但是性能非常糟糕,需要很长时间才能完成。

            var results = queryBuilder
                          .OrderBy(x => x.Vehicle.RangeId)
                          .ThenBy(x => x.Rate.Rental)
                          .GroupBy(x => x.Vehicle.RangeId)
                          .Select(x => x.OrderBy(o => o.Rate.Rental).FirstOrDefault())
                          .OrderBy(x => x.Rate.Rental);

任何帮助或建议都将不胜感激。我无法弄清楚为什么最初的查询没有保持一切正常。

我希望它通过RangeId订购车辆,然后通过租赁

在LINQ to Entities查询中,GroupBy之前的任何排序都将被忽略。您甚至不会在执行的SQL中看到它。这是因为EntityFramework采用分组表达式排序依据(在您的案例中为x => x.Vehicle.RangeId)。为什么?

LINQ的GroupBy看起来与SQL的GROUP BY相似,但实际上却大不相同。

SQL中的GROUP BY是"破坏性的",我的意思是除了GROUP BY中的列之外的任何信息都会丢失(聚合表达式除外)。如果你这样做。。。

SELECT Brand, COUNT(*) 
FROM Cars
GROUP BY Brand

您只能看到CCD_ 7及其计数。你看不到车队里的车。

这正是LINQ的GroupBy所做的:它生成完整对象的组。原始数据中的所有信息仍然存在。你会看到汽车按品牌分组。

这意味着将GroupBy转换为GROUP BY的ORM很难构建结果集。LINQ to SQL就是这么做的。它首先执行GROUP BY查询,然后需要单独的查询(实际上每组一个)来弥补"丢失"的数据。

EF以不同的方式实现CCD_ 12。它在一个查询中获取所有数据,然后在内存中构建组。您不会在生成的SQL中看到GROUP BY。您看到的是ORDER BY。我认为EF更喜欢排序的SQL查询结果,以便在内存中进行更高效的处理。(我可以想象与管道中的其他LINQ语句结合得更好)。

这就是为什么GroupBy之前的任何排序都被忽略的原因。以及为什么您只能在分组后应用排序。

的性能绝对糟糕

从这里很难判断为什么会这样。也许你可以在内存中进行排序:

var results = queryBuilder
              .GroupBy(x => x.Vehicle.RangeId)
              .Select(x => x.OrderBy(o => o.Rate.Rental).FirstOrDefault())
              .Select(o => new { o.Rate.Rental, o }
              .AsEnumerable()
              .OrderBy(x => x.Rental);

但这也可能是一个索引问题。如果在Rate.Rental上没有合适的索引,那么按该列排序的成本很高。

最新更新