我的LINQ查询是以零碎的方式构建的,如下所示:
var initialQuery = from item in MyContext where xxx == yyy select item;
var furtherQuery = from item in initialQuery where bla == foo select new { some stuff };
// more code here...
// eventually:
var yetAnotherQuery = (from item in furtherQuery ...)
.OrderBy(my_condition);
// As far as I know, the following query should still maintain the order of the previous one
// see: https://stackoverflow.com/questions/911942/are-subqueries-in-linqtosql-guaranteed-to-be-in-the-same-order-as-their-parent
var stillAnotherQuery = (from item in yetAnotherQuery
select item.data_I_care_about)
.Distinct();
// And finally...
var finalQuery = stillAnotherQuery.Skip(PageIndex).Take(PageSize);
但是我在调用Skip()
时遇到异常,说没有订购查询!
显然,我在上面的代码注释中指出的是referenced SO question并不完全正确。实际上another SO answer表示不保证该订单的保存。
有谁知道做我想要完成的事情的好方法?
我考虑在我的中间结果中简单地包含ROW_NUMBER
,并在最后按顺序排序,但我找不到通过LINQ在我的结果中获得ROW_NUMBER
的方法。
我看到有几个other SO questions在那里试图get the ROW_NUMBER,但就我所见,它们都是客户端。
我似乎把自己描绘成一个角落。 有人知道(LINQ友好的)出路吗?
有些人建议我在Distinct()
之前执行OrderBy()
。
我相信这会给我不同的结果。
想象一下,我有这个数据表
myRank | myData
-------+--------
3 | A
1 | B
2 | A
假设我按myRank
排序,我关心的数据是myData
,并想象我的原始代码是这样的:
var query = from item in MyTable
select item;
query = query.OrderBy(item => item.myRank);
var derivedQuery = from item in query // Note: we throw away myRank
select item.myData;
derivedQuery = derivedQuery.Distinct();
如果我交换OrderBy()
和Distinct()
的顺序,我会得到不同的结果。我不希望myRank
包含Distinct()
。
很抱歉,这是一个更大的过程的一部分,所以很难将所有细节都纳入这个问题。
但希望这有道理吗?
答案 0 :(得分:2)
问题不在于元素不再有序。
相反,问题是Distinct()返回IQueryable<T>
而OrderBy()返回IOrderedQueryable<TSource>
,这显然是分页与EF一起工作所必需的
交换Distinct()和OrderBy()步骤应该解决问题
修改
我建议大致如下:
var query = from item in MyTable
select item;
query = query.GroupBy(item => item.myData, item => item.myRank);
var derivedQuery = query.OrderBy(group => group.Min())
.Select(group.Key);
澄清:
myRank
的Min()排序将影响与myRank全局排序(升序)相同的顺序,然后执行Distinc()答案 1 :(得分:2)
由于其实施, Distinct
doesn't guarantee that the order is preserved. 由于这一点,您无法在其输出上运行Skip
,即使可以,也无法依靠Skip
的行为。
在运行OrderBy
之后,您需要运行Distinct
。考虑到你要做的事情,我没有看到通过单次调用OrderBy
来实现此目的的方法。 yetAnotherQuery
和stillAnotherQuery
中包含不同的元素,因此需要单独排序。
我看到它的方式,你有两个选择。您可以为yetAnotherQuery
一次访问数据库,然后在Distinct
本地运行OrderBy
和stillAnotherQuery
:
var yetAnotherQuery = (from item in furtherQuery ...)
.OrderBy(my_condition);
var stillAnotherQuery = (from item in yetAnotherQuery ...)
.Distinct()
.OrderBy(my_condition);
var finalQuery = stillAnotherQuery.Skip(PageIndex).Take(PageSize);
...或者您可以两次访问数据库,但在数据库服务器上进行所有排序和过滤:
var yaq_UnSorted = (from item in furtherQuery ...);
var yetAnotherQuery = yaq_UnSorted
.OrderBy(my_condition);
var stillAnotherQuery = (from item in yaq_UnSorted ...)
.Distinct()
.OrderBy(my_condition);
var finalQuery = stillAnotherQuery.Skip(PageIndex).Take(PageSize);
哪种解决方案最适合您将取决于您的优先事项。第一个将减少数据库的往返次数和传输的数据量,但它也会在您的应用服务器上使用更多资源。
Distinct
/ OrderBy
问题是一个非常常见的障碍。这是一个previous answer of mine on the subject.
答案 2 :(得分:1)
在{/ 1}}方法之后放置OrderBy
方法是否有用?
问题是Distinct
没有保留顺序。
<强>更新强>
现在我看到了问题。我认为您需要尝试使用Distinct
而不是GroupBy
。
这样的事情:
Distinct
答案 3 :(得分:0)
我认为问题不在于Distinct()
更改了订单 - 但它会返回“正常”IQueryable<T>
而不是IOrderedQueryable<T>
,这显然是Linq to Entities所必需的Skip
实施。
一种解决方案可能是颠倒OrderBy()
和Distinct()
方法的顺序,因此您先执行Distinct()
,然后再应用订单,然后使用{{1} }。