Entity framework core EF Core Diagnostics-每个上下文实例的查询计数

Entity framework core EF Core Diagnostics-每个上下文实例的查询计数,entity-framework-core,Entity Framework Core,我试图通过检查每个上下文实例的查询数量来检测EF。我们通常不希望对一个上下文进行超过10个左右的查询,所以我想用它来检查上下文是否被误用,例如在循环中进行查询调用,这会导致明显的性能问题 我基本上想说,如果针对任何给定上下文的查询数>X,那么记录一个错误,甚至抛出一个异常 我能找到的最接近的东西是使用事件id:RelationalEventId.CommandExecuted.Name,但是事件数据中没有上下文引用,因此无法在每个上下文的基础上跟踪它。事件计数器也不是真正可行的解决方案,因为它们

我试图通过检查每个上下文实例的查询数量来检测EF。我们通常不希望对一个上下文进行超过10个左右的查询,所以我想用它来检查上下文是否被误用,例如在循环中进行查询调用,这会导致明显的性能问题

我基本上想说,如果针对任何给定上下文的查询数>X,那么记录一个错误,甚至抛出一个异常

我能找到的最接近的东西是使用事件id:RelationalEventId.CommandExecuted.Name,但是事件数据中没有上下文引用,因此无法在每个上下文的基础上跟踪它。事件计数器也不是真正可行的解决方案,因为它们是全局计数器

有人知道我想做的事在其他方面是否可行吗


提前谢谢

我找到了一个解决方案,事实证明,在EF Core 3+中,上下文实例被添加到DbCommandInterceptor中的CommandCorrelatedEventData中,并在DbContext上添加了一个ContextId,这为您提供了跟踪查询计数所需的一切

以下是一个拦截器示例,用于限制每个上下文实例运行的命令数:

public class QueryInterceptor : DbCommandInterceptor
{
    // TODO: Use an expiring cache
    private readonly ConcurrentDictionary<DbContextId, int> _queryCountsPerContext = new();

    public override InterceptionResult<DbCommand> CommandCreating(CommandCorrelatedEventData eventData, InterceptionResult<DbCommand> result)
    {
        OnQueryExecuted(eventData);
        
        return base.CommandCreating(eventData, result);
    }

    private void OnQueryExecuted(CommandCorrelatedEventData eventData)
    {
        if (eventData.Context == null)
        {
            return;
        }
        
        if (!_queryCountsPerContext.TryGetValue(eventData.Context.ContextId, out var count))
        {
            count = 0;
        }

        count++;
        
        _queryCountsPerContext[eventData.Context.ContextId] = count;

        if (count > Constants.QueryLimitPerContextInstance)
        {
            throw new InvalidOperationException($"Too many queries for context instance! Limit: {Constants.QueryLimitPerContextInstance}");
        }
    }
}
public类QueryInterceptor:DbCommandInterceptor
{
//TODO:使用正在过期的缓存
私有只读ConcurrentDictionary_queryCountsPerContext=new();
公共覆盖拦截结果命令创建(CommandCorrelatedEventData事件数据,拦截结果)
{
OnQueryExecuted(事件数据);
返回base.CommandCreating(eventData,result);
}
已执行QueryExecuted上的私有void(CommandCorrelatedEventData事件数据)
{
if(eventData.Context==null)
{
返回;
}
if(!\u queryCountsPerContext.TryGetValue(eventData.Context.ContextId,out var count))
{
计数=0;
}
计数++;
_queryCountsPerContext[eventData.Context.ContextId]=计数;
if(计数>常数.QueryLimitPerContextInstance)
{
抛出新的InvalidOperationException($“上下文实例的查询太多!限制:{Constants.QueryLimitPerContextInstance}”);
}
}
}
要点和完整示例: