我有一个查询的以下部分(它是一个较大查询的末尾-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
上没有合适的索引,那么按该列排序的成本很高。