我可以在 EntityFramework Core 中配置拦截器吗?

Can I configure an interceptor in EntityFramework Core?

在旧时代(.net 核心之前)的 entity framework 6 中,如本 blog post 所示,有一种方法可以配置拦截器,它可以记录所有慢速查询,包括堆栈回溯。

[ 注意:在 3.0 版之前的 Entity Framework Core 中,这是不可能的,因此最初的问题是询问该怎么做。自提出这个问题以来,EF Core 的新选项和新版本已经发布。这个问题现在本质上是历史性的,后来添加的一些答案参考了其他较新版本的 EF Core,其中可能已重新引入拦截器,以实现与前核心时代的功能对等 entity framework]

2015 年的一个关于当时称为 EF7 的早期测试版的问题表明它不是 possible yet 在 asp.net vnext 早期测试版中。

然而,EF Core 的整个设计是可组合的,并且在关于 github 错误跟踪器 here 的讨论中,您可以使用一种技术 class 一些低level class like SqlServerConnection 然后覆盖其中的一些方法,以获得一些你可以在执行查询之前和之后挂钩的点,并在执行毫秒计时器值时添加一些低级别日志记录。

(编辑:2020 年删除了对 2015 年预发布信息的引用)

更新:Interception of database operations 现已在 EF Core 3.0 中可用。

原回答:


EF Core 还没有 "interceptors" 或类似的生命周期挂钩。此功能在此处跟踪:https://github.com/aspnet/EntityFramework/issues/626.

如果您只需要日志输出,那么覆盖低级组件可能是不必要的。许多低级别的 EF Core 组件已经产生了日志记录,包括查询执行的日志记录。您可以通过调用 DbContextOptionsBuilder.UseLoggerFactory(ILoggerFactory factory) 将 EF 配置为使用自定义记录器工厂。 (有关执行此操作的示例,请参阅 https://docs.asp.net/en/latest/fundamentals/logging.html and https://github.com/aspnet/Logging for more details on this logger interface.) EF Core produces some notable log events with well-define event IDs. (See Microsoft.EntityFrameworkCore.Infrastructure.CoreLoggingEventId in 1.0.0-rc2, which was renamed to justMicrosoft.EntityFrameworkCore.Infrastructure.CoreEventId for 1.0.0 RTM.) See https://docs.efproject.net/en/latest/miscellaneous/logging.html

如果您需要在 EF Core 组件已经生成的内容之外进行额外的日志记录,您将需要覆盖 EF Core 的低级别组件。最好通过覆盖现有组件并通过依赖项注入将此覆盖版本添加到 EF 来完成。这样做需要为 EF 配置自定义服务提供程序以供内部使用。这是由 DbContextOptionsBuilder.UseInternalServiceProvider(IServiceProvider services) 配置的,有关 EF 如何在内部使用服务的更多详细信息,请参阅 https://docs.efproject.net/en/latest/miscellaneous/internals/services.html

这是在 github 上从 ajcvickers 上找到的关于如何在 EF CORE 中使用拦截器的示例(回答此问题时为 2.2):

public class NoLockInterceptor : IObserver<KeyValuePair<string, object>>
{
    public void OnCompleted()
    {
    }

    public void OnError(Exception error)
    {
    }

    public void OnNext(KeyValuePair<string, object> value)
    {
        if (value.Key == RelationalEventId.CommandExecuting.Name)
        {
            var command = ((CommandEventData)value.Value).Command;

            // Do command.CommandText manipulation here
        }
    }
}

接下来,为 EF 诊断创建一个全局侦听器。类似于:

public class EfGlobalListener : IObserver<DiagnosticListener>
{
    private readonly NoLockInterceptor _noLockInterceptor = new NoLockInterceptor();

    public void OnCompleted()
    {
    }

    public void OnError(Exception error)
    {
    }

    public void OnNext(DiagnosticListener listener)
    {
        if (listener.Name == DbLoggerCategory.Name)
        {
            listener.Subscribe(_noLockInterceptor);
        }
    }
}

并将其注册为应用程序启动的一部分:

DiagnosticListener.AllListeners.Subscribe(new EfGlobalListener());

即将推出 EntityFramework 核心 3.0:https://github.com/aspnet/EntityFrameworkCore/issues/15066

它的工作方式与 EF 6 中的相同