【问题标题】:Intercepting CRUD operations on database using EF6 and filtering logs使用 EF6 拦截数据库上的 CRUD 操作并过滤日志
【发布时间】:2019-05-10 01:35:45
【问题描述】:

我正在尝试在我的 Windows 窗体应用程序中实现日志记录,并且我有这段代码可以让我在使用 Entity Framework 6 时拦截 CRUD 操作:

 class EFCommandInterceptor : IDbCommandInterceptor
    {
        public void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            LogInfo("NonQueryExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
        }

        public void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            LogInfo("NonQueryExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
        }

        public void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            LogInfo("ReaderExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
        }

        public void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            LogInfo("ReaderExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
        }

        public void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            LogInfo("ScalarExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
        }

        public void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            LogInfo("ScalarExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
        }

        private void LogInfo(string command, string commandText)
        {
            Console.WriteLine("Intercepted on: {0} :- {1} ", command, commandText);
        }
    }

然后我像这样添加拦截器:

public class FE6CodeConfig : DbConfiguration
{
    public FE6CodeConfig()
    {
        this.AddInterceptor(new EFCommandInterceptor());
    }
}

现在这一切都很好并且有效,我的意思是这是一个不错的小功能......但是,我只想在用户插入或删除记录时登录到我的数据库。

所以我需要 命令名(插入或删除)、表名行 ID,以及该表中的另一个字段。 .

现在我看到的是这些方法中有 DBCommand。有一个名为 Command Text 的属性...它提供如下输出:

Intercepted on: ReaderExecuting :- IsAsync: False, Command Text: INSERT [dbo].[Student]([FirstName], [StandardId], [LastName])
VALUES (@0, NULL, NULL)
SELECT [StudentID], [RowVersion] FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity()
Intercepted on: ReaderExecuted :- IsAsync: False, Command Text: INSERT [dbo].[Student]([FirstName], [StandardId], [LastName])
VALUES (@0, NULL, NULL)
SELECT [StudentID], [RowVersion] FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity()

我的意思是可能会从上面的字符串中解析所有内容...但是有没有更方便的方法来获取这些数据?

【问题讨论】:

  • 如果您使用原始查询执行,除了解析之外别无他法。但是,如果您使用 EF 实体,例如 .Add()、.Remove() 等 - 您可以在 SaveChanges 执行之前扫描实体在 DbContext 中的状态。
  • 如果命令文本对您来说不重要,您可以选择登录业务逻辑层的方法。
  • @eocron 是的,我正在处理实体......所以你的意思是完全跳过使用拦截器......嗯 :) 我可以试试......我的意思是,命令文本对我来说没问题如果它有真正的价值,而不是占位符......

标签: c# winforms logging entity-framework-6 interceptor


【解决方案1】:

仅借助 EF 的力量(未测试代码,但希望您能明白):

public void MyContext : DbContext
{
   public override int SaveChanges() //not relevant if it is new, you can do it in another method.
   {
       foreach(var e in this.ChangeTracker.Entries())
       {
           if(e.State == EntityState.Added)
           {
              //log here
           }
       }
       return base.SaveChanges();
   }
}

对于原始查询,您需要解析器。

【讨论】:

  • 哦,谢谢。这行得通...只是为了弄清楚如何获取表名及其字段的值...您知道该怎么做吗?顺便说一句,我不得不稍微改变你的代码。我需要这个才能工作:var e in this.ChangeTracker.Entries()
  • 谢谢您,添加以回答您的修复。是的,有可能,只需在实体中迭代它们。对于 actual (在 SQL 数据库中)字段和表的名称有点困难,因为需要侵入 EF 模型。不值得记录。
  • SaveChanges 是虚拟的,需要遮蔽它吗?
  • 一般来说你应该小心遵循这种方法,因为它会记录一些插入、更新、删除,即使SaveChanges失败。
  • 是的,这可能会失败,但日志记录通常是非事务性的,所以......只需处理它 =)
【解决方案2】:

作为一个选项而不是拦截命令执行,你可以登录业务逻辑层:

public class ProductBusiness
{
    ILogger logger;

    //...
    public void Create(Product p)
    {
        try
        {
            using (var db = new MyDbContext())
            {
                db.Products.Add(p);
                db.SaveChanges();
                logger.Log($"Create Product - {DateTime.Now} - Id:{p.Id}, Name:{p.Name}");
            }
        }
        catch (Exception ex)
        {
            logger.Log($"Error - {DateTime.Now} - {ex.ToString()}");
            throw;
        }
    }
    //...
}

【讨论】:

    猜你喜欢
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 2023-03-15
    • 2016-08-03
    • 2011-06-22
    • 1970-01-01
    相关资源
    最近更新 更多