【问题标题】:Can I configure an interceptor in EntityFramework Core?我可以在 EntityFramework Core 中配置拦截器吗?
【发布时间】:2016-06-06 15:02:54
【问题描述】:

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

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

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

然而,EF Core 的整个设计都是可组合的,在 github 错误跟踪器here 的讨论中,可能有一种技术可以在您子类化一些低级类(如 SqlServerConnection)然后覆盖其中的一些方法,为了获得一些分数,您可以在执行查询之前和之后挂钩,并在执行毫秒计时器值时添加一些低级日志记录。

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

【问题讨论】:

    标签: c# visual-studio-2015 entity-framework-core


    【解决方案1】:

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

    原答案:


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

    如果您想要的只是日志输出,则可能不需要覆盖低级组件。许多低级 EF Core 组件已经生成日志记录,包括查询执行的日志记录。您可以通过调用 DbContextOptionsBuilder.UseLoggerFactory(ILoggerFactory factory) 将 EF 配置为使用自定义记录器工厂。 (有关此记录器接口的更多详细信息,请参阅 https://docs.asp.net/en/latest/fundamentals/logging.htmlhttps://github.com/aspnet/Logging。)EF Core 生成一些具有明确定义的事件 ID 的值得注意的日志事件。 (请参阅 1.0.0-rc2 中的 Microsoft.EntityFrameworkCore.Infrastructure.CoreLoggingEventId,对于 1.0.0 RTM,它已重命名为 justMicrosoft.EntityFrameworkCore.Infrastructure.CoreEventId。)有关执行此操作的示例,请参阅 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

    【讨论】:

    • 服务的依赖注入听起来是最有前途的方法。
    • 从 EF Core 1.1 开始,DbContextOptionsBuilder 有一个方法 ReplaceService<Told, Tnew>(); ,可用于替换 EF 或 db Provider(SQL、Mysql 等)服务。例如:options.ReplaceService<DbProviderCompositeMethodCallTranslator, MyCustomCompositeMethodCallTranslator>(); ... 其中MyCustom 类继承自DbProvider 类和overrides 适当的方法。但我仍在寻找充当“拦截器”的内部服务。
    • @jhr 拦截器在 2.0 的路线图上(团队目前正在开发):github.com/aspnet/EntityFramework/wiki/Roadmap
    • 在 2019 年,我们似乎处于 EFCOre 2.2 时代的某个地方,而这个拦截器功能现在又存在了。
    【解决方案2】:

    以下是 ajcvickers 在 github 上找到的关于如何在 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());
    

    【讨论】:

    • 这是什么版本的?您可能想说,因为我怀疑它适用于 1.0 RC?我想知道我的问题是否更有意义,因为它是针对预发布版本的。但是您的回答很有用,因此我可以编辑我的问题以使其对.net核心更通用。 EF Core 2.0 应该有拦截器。
    • 我将当前版本信息放在我的回答中,我不知道这个功能到底是在哪个版本添加的。 DbInterceptor 不像 EF6 那样直接存在,您必须使用 DiagnosticListener
    【解决方案3】:

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

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2023-01-19
    • 1970-01-01
    相关资源
    最近更新 更多