gpt4 book ai didi

c# - Entity Framework 核心 : Guid Greater Than for Paging

转载 作者:太空宇宙 更新时间:2023-11-03 18:52:12 25 4
gpt4 key购买 nike

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 代码生成并手动解析表达式可能没问题(但如何?)

最佳答案

EF 核心 2.x:

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

Sets a callback that will be invoked to perform custom translation of this function. The callback takes a collection of expressions corresponding to the parameters passed to the function call. The callback should return an expression representing the desired translation.

下面的类通过定义几个自定义扩展方法来利用它来比较 Guid值并为它们注册自定义翻译,将方法调用表达式转换为二进制比较表达式,基本上模拟缺失的 > , >= , <<= Guid 运算符,允许将它们转换为 SQL 并在服务器端正确执行,只要数据库支持它们(SqlServer 支持)。

实现如下:

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);
});
}
}

您只需将以下行添加到您的上下文中 OnModelCreating覆盖:

GuidFunctions.Register(modelBuilder);

然后只需在您的查询中使用它们:

var result = DbContext.Entity
.Where(x => x.Id.IsGreaterThan(keyGuid))
.Take(10).ToList();

EF 核心 3.0:

HasTranslation现在接收并返回 SqlExpression实例,所以

return Expression.MakeBinary(type, left, right, false, method);

应替换为

return new SqlBinaryExpression(type, left, right, typeof(bool), null);

关于c# - Entity Framework 核心 : Guid Greater Than for Paging,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54920200/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com