【问题标题】:How to user use EF Command Interceptor to save data to database when intercepted command is inside transaction当拦截的命令在事务中时,如何用户使用 EF 命令拦截器将数据保存到数据库
【发布时间】:2021-07-09 10:22:23
【问题描述】:

我正在使用 EF 命令拦截器在命令执行后将一些数据保存到数据库。 (我有一些过滤器只在我想要的命令上运行它,所以它不会变成无限循环)

    class EFCommandInterceptor : IDbCommandInterceptor
    {
        public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            var log = new LogModel
            {
                DateTime = DateTime.Now,
                Log = "Log"
            };

            using (var context = new ApplicationDbContext())
            {
                context.Logs.Add(log);
                var res = context.SaveChangesAsync().Result;
            }
        }
    }

这在大多数情况下都可以正常工作。但是,如果我有任何需要在事务中记录的命令

using (TransactionScope transaction = new TransactionScope())
{
    // Some commands to intercept
}

我收到一个错误

var res = context.SaveChangesAsync().Result;

Win32Exception: The wait operation timed out

我尝试过延长连接超时和命令超时计时器,但引发相同错误需要更长的时间。

我也尝试在拦截器中创建一个新的 sql 连接和一个命令,但得到了同样的错误。

当 EF 命令拦截器从事务内部拦截命令时,有没有办法将数据保存到数据库中?

如果没有,拦截器是否有办法忽略事务内部的命令?

【问题讨论】:

    标签: entity-framework transactions interceptor


    【解决方案1】:

    一般来说,最好使用单独的日志框架进行日志记录,例如 log4net、NLog 或 Serilog,因为这些记录器在自己的线程中记录,并且应该对环境事务不敏感。

    在 .Net core 5 下使用 Serilog 进行的快速测试表明,即使在 TransactionScope 中调用它也会记录日志,并启用异步流,即回滚:

    using Serilog;
    using Serilog.Events;
    using Serilog.Sinks.MSSqlServer;
    using System.Transactions;
    
    using var ts = new TransactionScope(asyncFlowOption: TransactionScopeAsyncFlowOption.Enabled);
    
    var logger = new LoggerConfiguration()
        .WriteTo
        .MSSqlServer(
            connectionString: @"Server=.\sqlserver;Database=Test;Integrated Security=SSPI;",
            sinkOptions: new MSSqlServerSinkOptions { TableName = "Logs" })
        .CreateLogger();
    logger.Information("info");
    
    ts.Dispose(); // Rolls back. Added for clarity. Dispose happens anyway.
    

    每次运行都会将日志记录整齐地写入测试数据库。

    这里,Logs 是 Serilog 在未配置任何其他内容时所期望的标准日志记录表:

    CREATE TABLE [Logs] (
    
       [Id] int IDENTITY(1,1) NOT NULL,
       [Message] nvarchar(max) NULL,
       [MessageTemplate] nvarchar(max) NULL,
       [Level] nvarchar(128) NULL,
       [TimeStamp] datetime NOT NULL,
       [Exception] nvarchar(max) NULL,
       [Properties] nvarchar(max) NULL
    
       CONSTRAINT [PK_Logs] PRIMARY KEY CLUSTERED ([Id] ASC) 
    );
    

    请注意,Serilog 建议使用静态记录器对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-21
      相关资源
      最近更新 更多