EF Core自定义扩展查询报LINQ表达式无法转换错误如何解决
问题原因
EF Core 3.1的LINQ转SQL翻译器仅支持识别EF官方定义的标准查询运算符,无法解析你自定义的CustomWhere扩展方法的逻辑,尤其是该方法被用在查询内部的let子查询中时,会直接触发翻译失败错误。
解决方案
方案1:去掉自定义扩展,直接用原生条件拼接
你可以直接将动态判断逻辑写到Where条件里,不需要封装扩展,EF可以直接翻译这种判断逻辑,和你原有CustomWhere的效果完全一致:
var users = ( from user in _context.Users let userChange = _context.UsersChange .Where(e => string.IsNullOrEmpty(request.RegisterName) || e.RegisterName == request.RegisterName) .FirstOrDefault() select new { test = userChange }).FirstOrDefault();
这种写法会被EF直接翻译成SQL的OR判断,不会触发翻译错误。
方案2:如果一定要封装扩展,仅用于根查询分步拼接
如果你的动态过滤是作用在根IQueryable上,可以在触发查询执行前分步拼接条件,不要写到查询内部的子查询/let子句里:
// 先构造基础查询 var query = _context.Users.AsQueryable(); // 动态拼接过滤条件 if(!string.IsNullOrEmpty(request.RegisterName)) { query = query.Where(u => u.RegisterName == request.RegisterName); } // 执行查询 var user = query.FirstOrDefault();
方案3:通用动态过滤封装使用表达式树实现
如果确实需要封装通用的条件过滤能力,你需要基于表达式树构造通用的判断逻辑,示例如下:
public static class PredicateBuilder { public static IQueryable<T> WhereIf<T>( this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate) { return condition ? query.Where(predicate) : query; } } // 仅能用于根查询的外部拼接,不可用在查询内部的子查询、let子句中 var query = _context.Users .WhereIf(!string.IsNullOrEmpty(request.RegisterName), u => u.RegisterName == request.RegisterName);
注意:上述
WhereIf扩展仅可用于根查询的外部拼接,依旧不能放到查询内部的let子句、子查询中使用,否则EF还是无法翻译。
补充说明
你原有CustomWhere的逻辑存在写反的问题:当前实现是isTrue为true时返回原集合,false时加过滤。你传入的参数是string.IsNullOrEmpty(request.RegisterName)作为isTrue,也就是注册名为空时不过滤,不为空时加过滤,如果这不是你预期的逻辑,需要调整判断条件的顺序。
内容的提问来源于stack exchange,提问作者Wideflow
相关产品推荐
相关产品推荐

