我们可以使用Skip(),Take()和OrderBy()来控制LINQ表达式顺序吗?

Rob*_*nik 10 mysql linq linq-to-entities devart dotconnect

我正在使用LINQ to Entities来显示分页结果.但我在使用的组合问题Skip(),Take()OrderBy()调用.

一切正常,除了OrderBy()分配得太晚.之后的结果集已被削减它的执行Skip()Take().

因此,每个结果页面都按顺序排列.但是,对一页数据进行排序,而不是对整个集合进行排序,然后使用Skip()和限制这些记录Take().

如何设置这些语句的优先级?

我的例子(简化)

var query = ctx.EntitySet.Where(/* filter */).OrderByDescending(e => e.ChangedDate);
int total = query.Count();
var result = query.Skip(n).Take(x).ToList();
Run Code Online (Sandbox Code Playgroud)

一种可能(但不好)的解决方案

一种可能的解决方案是将聚簇索引应用于按列排序,但此列经常更改,这会降低插入和更新时的数据库性能.我真的不想那样做.

编辑

我运行ToTraceString()了我的查询,我们实际上可以看到order by应用于结果集.不幸的是最后.:(

SELECT 
-- columns
FROM  (SELECT 
    -- columns
    FROM   (SELECT -- columns
        FROM ( SELECT 
            -- columns
            FROM table1 AS Extent1
            WHERE  EXISTS (SELECT 
                -- single constant column
                FROM table2 AS Extent2
                WHERE (Extent1.ID = Extent2.ID) AND (Extent2.userId = :p__linq__4)
            )
        )  AS Project2
        limit 0,10  ) AS Limit1
    LEFT OUTER JOIN  (SELECT 
        -- columns
        FROM table2 AS Extent3 ) AS Project3 ON Limit1.ID = Project3.ID
UNION ALL
    SELECT 
    -- columns
    FROM   (SELECT -- columns
        FROM ( SELECT 
            -- columns
            FROM table1 AS Extent4
            WHERE  EXISTS (SELECT 
                -- single constant column
                FROM table2 AS Extent5
                WHERE (Extent4.ID = Extent5.ID) AND (Extent5.userId = :p__linq__4)
            )
        )  AS Project6
        limit 0,10  ) AS Limit2
    INNER JOIN table3 AS Extent6 ON Limit2.ID = Extent6.ID) AS UnionAll1
ORDER BY UnionAll1.ChangedDate DESC, UnionAll1.ID ASC, UnionAll1.C1 ASC
Run Code Online (Sandbox Code Playgroud)

Rob*_*nik 4

我的解决方案

我已经设法解决了这个问题。不要误会我的意思。到目前为止我还没有解决优先级问题,但我已经减轻了它。

我做了什么?

这是我在得到Devart答复之前一直使用的代码。如果他们无法解决这个问题,我最终将不得不使用此代码。

// get ordered list of IDs
List<int> ids = ctx.MyEntitySet
    .Include(/* Related entity set that is needed in where clause */)
    .Where(/* filter */)
    .OrderByDescending(e => e.ChangedDate)
    .Select(e => e.Id)
    .ToList();

// get total count
int total = ids.Count;

if (total > 0)
{
    // get a single page of results
    List<MyEntity> result = ctx.MyEntitySet
        .Include(/* related entity set (as described above) */)
        .Include(/* additional entity set that's neede in end results */)
        .Where(string.Format("it.Id in {{{0}}}", string.Join(",", ids.ConvertAll(id => id.ToString()).Skip(pageSize * currentPageIndex).Take(pageSize).ToArray())))
        .OrderByDescending(e => e.ChangedOn)
        .ToList();
}
Run Code Online (Sandbox Code Playgroud)

首先,我得到了我的实体的有序 ID。即使对于较大的数据集,仅获取 ID 也具有良好的性能。MySql 查询非常简单并且性能非常好。在第二部分中,我对这些 ID 进行分区并使用它们来获取实际的实体实例。

考虑到这一点,这应该比我一开始的方式执行得更好(如我的问题中所述),因为由于简化的查询,获得总计数要快得多。第二部分实际上非常非常相似,除了我的实体是通过它们的 ID 返回而不是使用Skipand进行分区Take...

希望有人会发现这个解决方案有帮助。