LINQ - 如何保存我的(复杂)结果?

时间:2011-09-09 21:31:50

标签: linq linq-to-entities

我的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()

很抱歉,这是一个更大的过程的一部分,所以很难将所有细节都纳入这个问题。

但希望这有道理吗?

4 个答案:

答案 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);

澄清:

  • group by将导致dinstinct键(myData)无论如何
  • 按每组myRank的Min()排序将影响与myRank全局排序(升序)相同的顺序,然后执行Distinc()

答案 1 :(得分:2)

由于其实施, Distinct doesn't guarantee that the order is preserved. 由于这一点,您无法在其输出上运行Skip,即使可以,也无法依靠Skip的行为。

在运行OrderBy之后,您需要运行Distinct 。考虑到你要做的事情,我没有看到通过单次调用OrderBy来实现此目的的方法。 yetAnotherQuerystillAnotherQuery中包含不同的元素,因此需要单独排序。

我看到它的方式,你有两个选择。您可以为yetAnotherQuery一次访问数据库,然后在Distinct本地运行OrderBystillAnotherQuery

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没有保留顺序。

参考:http://programminglinq.com/blogs/marcorusso/archive/2008/07/20/use-of-distinct-and-orderby-in-linq.aspx

<强>更新

现在我看到了问题。我认为您需要尝试使用Distinct而不是GroupBy

这样的事情:

Distinct

答案 3 :(得分:0)

我认为问题不在于Distinct()更改了订单 - 但它会返回“正常”IQueryable<T>而不是IOrderedQueryable<T>,这显然是Linq to Entities所必需的Skip实施。

一种解决方案可能是颠倒OrderBy()Distinct()方法的顺序,因此您先执行Distinct(),然后再应用订单,然后使用{{1} }。