Mysql 我们可以用Skip()、Take()和OrderBy()控制LINQ表达式的顺序吗

Mysql 我们可以用Skip()、Take()和OrderBy()控制LINQ表达式的顺序吗,mysql,linq,linq-to-entities,devart,dotconnect,Mysql,Linq,Linq To Entities,Devart,Dotconnect,我使用LINQ to实体来显示分页结果。但是我在结合使用Skip()、Take()和OrderBy()调用时遇到了问题 一切正常,只是OrderBy()分配得太晚了。它是在结果集被Skip()和Take()削减后执行的 因此,结果的每一页都有顺序排列的项目。但排序是在一页少量数据上完成的,而不是对整个集合进行排序,然后使用Skip()和Take()限制这些记录 如何设置这些语句的优先级? 我的例子(简化) 一个可能的(但不好的)解决方案 一种可能的解决方案是将聚集索引应用于按列排序,但此列经常更

我使用LINQ to实体来显示分页结果。但是我在结合使用
Skip()
Take()
OrderBy()
调用时遇到了问题

一切正常,只是
OrderBy()
分配得太晚了。它是在结果集被
Skip()
Take()
削减后执行的

因此,结果的每一页都有顺序排列的项目。但排序是在一页少量数据上完成的,而不是对整个集合进行排序,然后使用
Skip()
Take()
限制这些记录

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

我的例子(简化) 一个可能的(但不好的)解决方案 一种可能的解决方案是将聚集索引应用于按列排序,但此列经常更改,这会降低数据库在插入和更新时的性能。我真的不想这么做

编辑 我在查询中运行了
ToTraceString()
,我们可以实际看到order by何时应用于结果集。不幸的是在最后(

单向:

var query = ctx.EntitySet.Where(/* filter */).OrderBy(/* expression */).ToList();
int total = query.Count;
var result = query.Skip(n).Take(x).ToList();

跳过前将其转换为列表。请注意,这不是很有效…

假设您的注释中不允许将值持久化到列表中:

没有办法完全减少迭代次数,正如您所希望的(我也会尝试,生活在希望中)。将迭代次数减少一次会很好。是否可以只获取一次计数并缓存/会话它?然后您可以:

int total = ctx.EntitySet.Count;  // Hopefully you can not repeat doing this.
var result = ctx.EntitySet.Where(/* filter */).OrderBy(/* expression */).Skip(n).Take(x).ToList();

希望您能够以某种方式缓存计数,或者避免每次都需要它。即使您不能,这也是您所能做的最好的事情。

您是否绝对确定已关闭排序?SQL看起来是什么样子

你能按如下顺序重新排列你的代码并发布输出吗

// Redefine your queries. 
var query = ctx.EntitySet.Where(/* filter */).OrderBy(e => e.ChangedDate); 
var skipped = query.Skip(n).Take(x);

// let's look at the SQL, shall we?
var querySQL = query.ToTraceString();
var skippedSQL = skipped.ToTraceString();

// actual execution of the queries...
int total = query.Count(); 
var result = skipped.ToList(); 
编辑:


我绝对肯定。你可以检查我的“编辑”来查看我的查询的跟踪结果,在这种情况下,跳过跟踪结果是必要的。计数并不重要


是的,我明白了。哇,这是一个难题。甚至可能是一个彻头彻尾的错误。我注意到您没有使用SQL Server…您使用的是什么数据库?看起来可能是MySQl。

我没有直接使用Linq to Entities,但它应该有一种方法在需要时将特定的存储过程挂接到特定的位置。(Linq to SQL做到了。)如果是这样,您可以将此查询转换为一个存储过程,精确地执行所需操作,并高效地执行。

您能否创建一个示例来说明问题并将其发送给我们(support*devart*com,主题为“EF:Skip,Take,OrderBy”)?
希望我们能够帮助您。
您也可以使用我们的或。

我的解决方案与我们联系 我已经设法解决了这个问题。别误会我的意思。我还没有解决优先级问题,但我已经缓解了它

我做了什么?

这是我一直使用的代码,直到我从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();
}
//获取ID的有序列表
列表ID=ctx.MyEntitySet
.包括(/*where子句中需要的相关实体集*/)
。其中(/*过滤器*/)
.OrderByDescending(e=>e.ChangedDate)
.选择(e=>e.Id)
.ToList();
//获取总计数
int total=ids.Count;
如果(总数>0)
{
//获取一页结果
列表结果=ctx.MyEntitySet
.包括(/*相关实体集(如上所述)*/)
.包括(/*最终结果中需要的其他实体集*/)
.Where(string.Format({{{0}}中的it.Id),string.Join(“,”,ids.ConvertAll(Id=>Id.ToString()).Skip(pageSize*currentPageIndex).Take(pageSize.ToArray()))
.OrderByDescending(e=>e.ChangedOn)
.ToList();
}
首先,我获取实体的有序ID。即使数据集较大,仅获取ID的性能也很好。MySql查询非常简单,性能也非常好。在第二部分中,我对这些ID进行分区,并使用它们获取实际的实体实例

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


希望有人会觉得这个解决方案很有帮助。

这不是一个选项,因为实体集有太多记录。这就是为什么我首先使用分页的原因。是的,我知道。它可能效率不高,但对于较小的记录集,它确实有效。我没有小结果集的优势…:(缓存
Count
并不能真正解决问题。如果我将
OrderBy
子句移动到最后一个查询(因此它与
Skip
Take
组合在一起)我得到了相同的结果。在将结果剪切为子集后,将应用顺序。缓存计数只会为我保存一个DB调用。但结果仍然不正确。在我的代码中,查询运算符的顺序将确保跳过并按照预期的顺序进行操作。我猜您的查询不会以预期的顺序返回结果ed order。您是否使用(A)
.ToTraceString()
或(B)sql探查器()查看过sql?如果您直接对数据库运行sql,是否得到了预期的顺序?我绝对肯定。您可以检查我的“编辑”要查看我的查询的跟踪结果,跳过
跟踪结果在这种情况下是必须的。计数不是很重要。@Robert Koritnik:我回答了我的问题。我想可能是你发现了一个错误。你在用什么数据库?MySQL?Postgres?正如我的标签中所说的,我在用MySQL。我在用Devart的dotConnect。你能试一下吗SQL小姐怎么样?所以你会做所有的事情
// Redefine your queries. 
var query = ctx.EntitySet.Where(/* filter */).OrderBy(e => e.ChangedDate); 
var skipped = query.Skip(n).Take(x);

// let's look at the SQL, shall we?
var querySQL = query.ToTraceString();
var skippedSQL = skipped.ToTraceString();

// actual execution of the queries...
int total = query.Count(); 
var result = skipped.ToList(); 
// 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();
}