升级EF Core 3.1后OrderBy方法失效,求解决方案
EF Core 3.1升级后OrderBy无法正常工作的解决方案
问题出在你定义的排序键选择器Expression<Func<TEntity, object>> sortingKeySelector上:当返回类型为object时,EF Core会对原始类型(比如string、int)做装箱操作,生成额外的Convert表达式节点。而EF Core 3.1默认禁用了隐式客户端评估,无法将这种带装箱的表达式翻译成SQL,因此抛出异常。
以下是几种可行的解决方法:
1. 改为强类型泛型排序键(推荐)
修改PageAsync方法为泛型方法,将排序键选择器的返回类型改为具体的泛型参数TKey,这样EF Core能直接解析原始类型,生成正确的排序SQL:
public virtual async Task<IPagedList<TEntity>> PageAsync<TKey>( Expression<Func<TEntity, bool>> filter = null, Expression<Func<TEntity, TKey>> sortingKeySelector = null, SortingOrder sortingOrder = SortingOrder.Ascending, string include = "", int pageIndex = 1, int pageSize = 1000) { // 原有初始化query的逻辑... if (sortingKeySelector != null) { query = sortingOrder == SortingOrder.Ascending ? query.OrderBy(sortingKeySelector) : query.OrderByDescending(sortingKeySelector); } var result = await Paged(query, pageIndex, pageSize).ToListAsync(); // 后续处理逻辑... }
调用时只需指定排序键的类型即可,比如:
await PageAsync<string>(filter: r => !r.IsDeleted, sortingKeySelector: r => r.Name);
2. 手动拆解装箱表达式(兼容旧方法签名)
如果无法修改方法签名以兼容现有调用,可以手动移除表达式中的Convert节点,还原原始类型的表达式:
先定义一个表达式转换的扩展方法:
public static class ExpressionExtensions { public static Expression<Func<TEntity, TKey>> Unbox<TEntity, TKey>(this Expression<Func<TEntity, object>> expression) { var body = expression.Body; // 移除装箱产生的Convert节点 if (body.NodeType == ExpressionType.Convert) { body = ((UnaryExpression)body).Operand; } return Expression.Lambda<Func<TEntity, TKey>>(body, expression.Parameters); } }
然后在PageAsync中使用该方法转换排序键:
// 假设排序键类型为string,实际使用时需根据场景替换为对应类型 var typedSelector = sortingKeySelector.Unbox<TEntity, string>(); query = sortingOrder == SortingOrder.Ascending ? query.OrderBy(typedSelector) : query.OrderByDescending(typedSelector);
注意:这种方法需要提前知道排序键的具体类型,如果类型不确定,可能需要结合反射处理,但复杂度较高,优先推荐第一种泛型方案。
3. 临时允许客户端评估(不推荐)
如果以上两种方法都无法实施,可以临时允许EF Core进行客户端评估,但这会导致排序逻辑在内存中执行,大数据量场景下会严重影响性能:
在DbContext的配置中添加:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer("你的数据库连接字符串") .ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.ClientEvaluationWarning)); }
内容的提问来源于stack exchange,提问作者Zoran G
相关产品推荐
相关产品推荐

