You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么运行时表达式会导致Entity Framework Core 5缓存键冲突?

问题根本成因

这是 EF Core 5.x版本的已知官方Bug,问题出在ExpressionEqualityComparer的内部实现逻辑:

  • EF的查询编译缓存是全局生效的,和查询是否为非跟踪状态无关,只要执行查询就会走缓存键的相等性比较逻辑
  • 你动态生成多个过滤Lambda时用了多个同名(均为e)但不同实例的ParameterExpression参数,在用And/Or扩展方法拼接表达式后,EF的表达式相等性比较器在对比Lambda时,内部使用了没有做重复键校验的普通Dictionary存储参数映射,遇到同名不同实例的参数时就会直接抛出"相同键已存在"的异常。

你当前的动态生成参数名的临时方案虽然可以绕开报错,但会导致逻辑完全相同的查询因为参数名不一致无法复用编译缓存,缓存命中率大幅下降,高并发场景下会有明显的性能损耗,不建议长期使用。

更合理的修复方案

方案1:升级EF Core版本(最优解)

该Bug在EF Core 6.0及以上版本已经被官方修复,如果你的项目可以升级.NET运行时版本,直接升级到.NET 6+配套使用EF Core 6.0+即可,无需修改现有业务代码。

方案2:修改表达式拼接逻辑(兼容EF Core 5.x)

如果你暂时无法升级版本,只需调整And/Or扩展方法的实现,将所有待拼接Lambda的参数替换为同一个ParameterExpression实例即可,既可以绕开Bug,也不会影响查询缓存的复用:

  1. 首先实现参数替换的表达式访问器
public class ParameterReplaceVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _oldParam;
    private readonly ParameterExpression _newParam;

    public ParameterReplaceVisitor(ParameterExpression oldParam, ParameterExpression newParam)
    {
        _oldParam = oldParam;
        _newParam = newParam;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == _oldParam ? _newParam : base.VisitParameter(node);
    }
}
  1. 修改And/Or扩展方法实现
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
    if (left == null) return right;
    if (right == null) return left;
    // 将右侧Lambda的参数替换为和左侧一致的实例
    var adjustedRightBody = new ParameterReplaceVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body);
    return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left.Body, adjustedRightBody), left.Parameters);
}

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
    if (left == null) return right;
    if (right == null) return left;
    var adjustedRightBody = new ParameterReplaceVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body);
    return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left.Body, adjustedRightBody), left.Parameters);
}

该问题属于EF Core 5.x的原生Bug,并非你的业务实现疏漏导致,不需要提交新的Github Issue。

内容的提问来源于stack exchange,提问作者Patricio Leonel Filice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 11:18:03