使用Specification模式组合规约时LINQ表达式无法翻译为SQL问题求助
问题根源
你遇到的无法翻译异常的核心原因是两个待组合的表达式树使用了不同的ParameterExpression实例:
- 你从
leftSpec和rightSpec拿到的两个Expression<Func<T, bool>>各自持有独立的参数实例,虽然二者类型都是T,但在表达式树的判定逻辑中属于完全不同的两个对象 - 你直接拼接两个表达式的Body后,新的Lambda只传入了
leftSpec的参数作为入参,rightSpec的Body中引用的还是自己原有的参数实例,EF Core无法识别这个未在Lambda参数列表中声明的参数,因此判定为无法翻译为SQL。
修复方案
你需要先实现一个参数重绑定的表达式访问者,将第二个表达式的参数替换为第一个表达式的参数实例,再做拼接:
1. 实现参数替换访问者
internal class ParameterRebinder : ExpressionVisitor { private readonly ParameterExpression _oldParam; private readonly ParameterExpression _newParam; public ParameterRebinder(ParameterExpression oldParam, ParameterExpression newParam) { _oldParam = oldParam; _newParam = newParam; } protected override Expression VisitParameter(ParameterExpression node) { return node == _oldParam ? _newParam : base.VisitParameter(node); } }
2. 修改CombinedSpecification的FilterExpr方法
public override Expression<Func<T, bool>> FilterExpr() { Expression<Func<T, bool>> firstExpr = this.leftSpec.FilterExpr(); Expression<Func<T, bool>> secondExpr = this.rightSpec.FilterExpr(); // 将第二个表达式的参数替换为第一个表达式的参数 var rebinder = new ParameterRebinder(secondExpr.Parameters.Single(), firstExpr.Parameters.Single()); var rewrittenSecondBody = rebinder.Visit(secondExpr.Body); BinaryExpression combined = Expression.AndAlso(firstExpr.Body, rewrittenSecondBody); return Expression.Lambda<Func<T, bool>>(combined, firstExpr.Parameters.Single()); }
修改后组合后的表达式所有属性访问都指向同一个参数实例,EF Core就可以正常解析为SQL语句执行,不会触发无法翻译的异常。
内容的提问来源于stack exchange,提问作者gst
相关产品推荐
相关产品推荐

