C# 实体框架核心:Guid大于,用于分页

C# 实体框架核心:Guid大于,用于分页,c#,.net,entity-framework-core,C#,.net,Entity Framework Core,SQL Server在跳过/接受大型表(>1000000行)时变得非常慢。tables键列类型是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.En

SQL Server在跳过/接受大型表(>1000000行)时变得非常慢。tables键列类型是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核心解决方案?如果可以拦截SQL代码生成并手动解析表达式(但如何解析?)EF Core 2.x

从v2.0开始,EF Core支持所谓的。它没有很好的文档记录,通常用于映射一些数据库功能。但fluent API还允许您通过以下方法提供自定义翻译:

设置将被调用以执行此函数的自定义转换的回调。回调获取与传递给函数调用的参数相对应的表达式集合。回调应该返回表示所需转换的表达式


下面的类通过定义几个用于比较
Guid
值的自定义扩展方法来利用它,并为它们注册自定义转换,将方法调用表达式转换为二进制比较表达式,基本上模拟缺少的
=
您可以自己用EF-Core编写SQL查询,如下所示:或者,谢谢,这将是我最后的选择。它是一个通用组件,可以处理任何表,包括一些包含复合键的表。这并不容易,因为需要更多的自定义sql代码生成。@Florian如果没有
OrderBy()
子句,您的代码将无法工作。除非指定了
orderby
子句,否则查询结果中没有隐含的顺序。即使
ID
是聚集索引,联接和并行执行也会改变结果的显示方式。
public static class GuidFunctions
{
    public static bool IsGreaterThan(this Guid left, Guid right) => left.CompareTo(right) > 0;
    public static bool IsGreaterThanOrEqual(this Guid left, Guid right) => left.CompareTo(right) >= 0;
    public static bool IsLessThan(this Guid left, Guid right) => left.CompareTo(right) < 0;
    public static bool IsLessThanOrEqual(this Guid left, Guid right) => left.CompareTo(right) <= 0;
    public static void Register(ModelBuilder modelBuilder)
    {
        RegisterFunction(modelBuilder, nameof(IsGreaterThan), ExpressionType.GreaterThan);
        RegisterFunction(modelBuilder, nameof(IsGreaterThanOrEqual), ExpressionType.GreaterThanOrEqual);
        RegisterFunction(modelBuilder, nameof(IsLessThan), ExpressionType.LessThan);
        RegisterFunction(modelBuilder, nameof(IsLessThanOrEqual), ExpressionType.LessThanOrEqual);
    }
    static void RegisterFunction(ModelBuilder modelBuilder, string name, ExpressionType type)
    {
        var method = typeof(GuidFunctions).GetMethod(name, new[] { typeof(Guid), typeof(Guid) });
        modelBuilder.HasDbFunction(method).HasTranslation(parameters =>
        {
            var left = parameters.ElementAt(0);
            var right = parameters.ElementAt(1);
            return Expression.MakeBinary(type, left, right, false, method);
        });
    }
}
GuidFunctions.Register(modelBuilder);
var result = DbContext.Entity
    .Where(x => x.Id.IsGreaterThan(keyGuid))
    .Take(10).ToList();
return Expression.MakeBinary(type, left, right, false, method);
return new SqlBinaryExpression(type, left, right, typeof(bool), null);