SQL Server在大型表(> 1000000行)上使用Skip/Take会变得非常慢。表的键列类型是Guid,我知道最后读取的行。我试着加载下一页
var keyGuid = Guid.NewGuid(); // Key Guid of the last read row
// var result1 = DbContext.Entity.Where(x => x.Id > keyGuid).Take(10).ToList();
var result2 = DbContext.Entity.Where(x => x.Id.CompareTo(keyGuid) > 0).Take(10).ToList();
虽然第一种方法无法编译,但第二种方法在客户端计算查询(QueryClientEvaluationWarning),并且也没有用。
不幸的是,我无法以任何方式修改数据库。
有没有没有没有自定义SQL的“原生”EF Core解决方案?如果可以拦截SQL代码生成并手动解析表达式,那就没问题了(但是怎么做呢?)
2条答案
按热度按时间qf9go6mv1#
EF Core 2.x:
从v2.0开始,EF Core支持所谓的数据库标量函数Map。它没有很好的文档记录,通常用于Map一些数据库函数。但是fluent API还允许您通过HasTranslation方法提供自定义翻译:
设置一个回调,将调用该回调来执行此函数的自定义转换。回调接受与传递给函数调用的参数相对应的表达式集合。回调应该返回一个表示所需翻译的表达式。
下面的类通过定义几个自定义扩展方法来比较
Guid
值并为它们注册一个自定义转换,将方法调用表达式转换为二进制比较表达式,基本上模拟了缺少的>
,>=
,<
和<=
Guid运算符,这允许将它们转换为SQL并正确执行服务器端。只要数据库支持它们(SqlServer支持)。下面是实现:
您只需要将以下行添加到您的上下文
OnModelCreating
覆盖:然后在查询中使用它们:
EF Core 3.0:
HasTranslation
现在接收并返回SqlExpression
示例,因此应替换为
8yparm6h2#
EF 7
CompareTo
方法可以工作并生成缩进的sql查询。