在 dbcontext 中添加拦截器会出现 Microsoft.EntityFrameworkCore.Infrastruct.ManyServiceProvidersCreatedWarning 异常

pan*_*nis 4 .net c# entity-framework-core

我在 EF Core 7 中使用 .NET 7 有以下代码:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    base.OnConfiguring(optionsBuilder);

    optionsBuilder.AddInterceptors(new IgnoreTrackingInterceptor());
}

public class IgnoreTrackingInterceptor : IMaterializationInterceptor
{
    public object InitializedInstance(MaterializationInterceptionData materializationData, object instance)
    {
        if (instance is ISomeEntity someEntity)
            materializationData.Context.Entry(someEntity).State = EntityState.Detached;

        return instance;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用该应用程序一段时间后,它会抛出ManyServiceProvidersCreatedWarning异常。

An error was generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.ManyServiceProvidersCreatedWarning': More than twenty 'IServiceProvider' instances have been created for internal use by Entity Framework. This is commonly caused by injection of a new singleton service instance into every DbContext instance
Run Code Online (Sandbox Code Playgroud)

当我评论时,该optionsBuilder.AddInterceptors(new IgnoreTrackingInterceptor());应用程序可以正常运行几个小时。

我在这里做错了什么?

Iva*_*oev 6

问题是IMaterializationInterceptor是 EF Core ISingletonInterceptor接口之一,它

所有注册为单例服务的实体框架拦截器的基本接口。这意味着单个实例被多个DbContext实例使用。实现必须是线程安全的。

即使该接口不添加成员,EF Core 基础结构也会将其用作标记,并且确实期望实现在 DI 中注册为单例或静态实例,因为这些是 EF Core 服务提供者缓存密钥哈希代码的一部分,并且相等(通过引用进行比较)。

所以修改代码如下:

public class IgnoreTrackingInterceptor : IMaterializationInterceptor
{
    public static IgnoreTrackingInterceptor Instance { get; } = new();
    private IgnoreTrackingInterceptor() { }
    // the rest as is
}
Run Code Online (Sandbox Code Playgroud)

optionsBuilder.AddInterceptors(IgnoreTrackingInterceptor.Instance);
Run Code Online (Sandbox Code Playgroud)

问题应该得到解决。

  • 真的不确定为什么OP很难接受这个答案,因为它客观上是更正确的答案。谢谢伊万。 (2认同)