EF Core中Expression Visitor改写查询时访问局部变量参数属性报错问题
EF Core查询表达式改写时的翻译失败问题
场景说明
我尝试用Expression Visitor改写EF Core查询,将初始的对象相等判断,转换成逐个属性匹配的形式。
初始查询代码:
var contractSubjectKey = new ContractSubjectKey(subjectId, rank); insurance = context.Set<Insurance>() .FirstOrDefault(i => i.Key.ContractSubjectKey == contractSubjectKey);
预期改写后的表达式:
i => i.Key.ContractSubjectKey.Id == contractSubjectKey.Id
遇到的问题
左侧的MemberExpression属性访问处理正常,但右侧如果是代表局部变量的ParameterExpression,使用var right = Expression.Property(parameterExpression, "Id");生成表达式后,会触发LINQ表达式无法翻译的错误:
System.InvalidOperationException : The LINQ expression 'DbSet()
.Where(i => EF.Property(EF.Property(i, "Key"), "ContractSubjectKey").Id == __contractSubjectKey_0.Id)' could not be translated.
问题排查与解决思路
后续发现问题根源在于EF Core的IQueryTranslationPreprocessor已经提前提取并缓存了参数,等到IQueryExpressionInterceptor阶段再进行这类改写就无法被正确处理了。目前计划通过自定义IQueryTranslationPreprocessor或Postprocessor来解决该问题,但需要关注性能开销。
相关上下文代码
public record ContractSubjectKey(int Id, int Rank); //insurance.Key.ContractSubjectKey 实际是 ContractSubjectKeyInsurance,继承自 ContractSubjectKey public record ContractSubjectKeyInsurance : ContractSubjectKey { public ContractSubjectKeyInsurance(int Id, int Rank) : base(Id, Rank) { } public ContractSubjectKeyInsurance(int Id, int Rank, int InsuranceKeyId) : base(Id, Rank) { _insuranceKeyId = InsuranceKeyId; } private int _insuranceKeyId; } public record InsuranceKey(int Id, ContractSubjectKey ContractSubjectKey) { this.Id = Id; _contractSubjectId = ContractSubjectKey.Id; _contractSubjectRank = ContractSubjectKey.Rank; this.ContractSubjectKey = new ContractSubjectKeyInsurance(ContractSubjectKey.Id, ContractSubjectKey.Rank, Id); }
内容的提问来源于stack exchange,提问作者Matus
相关产品推荐
相关产品推荐

