我有一个查询的以下部分(它是一个更大的查询的结尾 - 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之前被命令为。
然而。不是。它只是随机获得一个无序。有时它是第二便宜的。有时候是5号等等。出于某种原因,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);
任何帮助或指示将不胜感激。我无法确定为什么原始查询不能保持一切顺序。
答案 0 :(得分:3)
我希望它可以通过RangeId订购车辆,然后租借
在LINQ to Entities查询中,简单地忽略GroupBy
之前的任何排序。您甚至不会在执行的SQL中看到它。这是因为实体框架将分组表达式排序为(在您的情况下为x => x.Vehicle.RangeId
)。那是为什么?
LINQ的GroupBy
似乎与SQL的GROUP BY
相似,但实际上却完全不同。
GROUP BY
是“破坏性的”,我的意思是除GROUP BY
中的列以外的任何信息都会丢失(除了聚合表达式)。如果你这样做......
SELECT Brand, COUNT(*)
FROM Cars
GROUP BY Brand
...你只看到Brand
及其数量。你没有在小组中看到汽车。
这正是LINQ的GroupBy
所做的:它产生了完整的对象组。原始数据中的所有信息仍然存在。你会看到按品牌分组的汽车。
这意味着将GroupBy
翻译为GROUP BY
的ORM会让自己难以构建结果集。 LINQ to SQL就是这样做的。它首先执行GROUP BY
查询,然后需要单独的查询(实际上每组一个)以弥补“丢失”的数据。
EF以不同方式实施GroupBy
。它在一个查询中获取所有数据,然后在内存中构建组。您不会在生成的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
上没有正确的索引,那么按该列排序是很昂贵的。