Entity Framework入门教程(17)---记录和拦截数据库命令

记录和拦截数据库命令

这一节介绍EF6怎么记录和拦截发送给数据库的查询和操做命令。html

1.记录EF发送给数据库命令(DbContext.Database.Log)

之前给了查看EF发送给数据库的命令咱们须要借助数据库的追踪工具或者第三方追踪工具,如今EF6中提供了DbContext.Database.Log属性(Action<string>类型),使用这个属性咱们能够很方便地记录EF发送给数据库的命令。web

下边是一个栗子:数据库

        static void Main(string[] args)
        {
            using (EFDbContext context=new EFDbContext())
            {
                context.Database.Log = Console.WriteLine;
                var std1 = context.Students.Find(1);
                std1.Name = "newName";
                context.SaveChanges();
                Console.ReadKey();
            }
           
        }

输出以下:api

在上边的栗子中,Console.Write()方法属于Action<string>类型,因此能够赋值给Log属性。能够看到EF打开和关闭数据库,执行查询,和使用事务进行CUD都会被记录下来。mvc

咱们也能够自定义一个Action<string>委托的实例赋值给Log属性:app

public class Logger
{
    public static void Log(string message)
    {
        Console.WriteLine("EF Message: {0} ", message);
    }
}

class EF6Demo
{
    public static void DBCommandLogging()
    {
        using (var context = new SchoolDBEntities())
        {
                
            context.Database.Log =  Logger.Log;                
            var std1 = context.Students.Find(1);
            std1.Name = "newName";
            context.SaveChanges();
            Console.ReadKey();
        }
    }
}

 2.拦截EF生成的数据库命令(IDbCommandIntercepter)

EF6提供了拦截数据库的接口IDbCommandIntercepter,这个接口提供了拦截EF发送给数据库的命令的方法,咱们也能够使用这个接口实如今context的操做执行前或执行后去作一些自定义的操做(相似mvc/api中的filter)。由于DbContext执行操做的底层实现是利用ADO.NET进行ExecuteNonQueryExecuteScalar, 和ExecuteReader,因此咱们能够经过如NonQueryExecuted、NonQueryExecuting等方法进行拦截。异步

为了实现SQL命令拦截咱们首先要定义一个实现IDbCommandIntercepter接口的类:ide

    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);
        }
    }

能够看出,IDbCommandInterceptor 接口提供了6个方法,分别用于在ADO.NET执行ExecuteNonQuery(),ExcuteReader(),ExcuteScalar()方法的执行前/后拦截命令。这个栗子目的是:记录context的操做是不是异步和发送到数据库的命令。咱们也能够使用这些方法来实现自定义逻辑(和filter简直如出一辙有木有)。工具

接下来把拦截器添加到配置中去,两种实现方式:post

① 经过配置文件,在app.config或web.config中添加以下节点

<entityFramework>
    <interceptors>
        <interceptor type="EF6DBFirstTutorials.EFCommandInterceptor, EF6DBFirstTutorials">
        </interceptor>
    </interceptors>
</entityFramework>

②代码配置

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

配置完成咱们就能够记录EF发送给数据库的命令了,一个栗子:

var newStudent =  new Student() { FirstName = "Bill" };

using (var context = new SchoolDBEntities())
{
    context.Students.Add(newStudent);
    context.SaveChanges();
}

栗子输出为:

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系列目录连接:Entity Franmework系列教程汇总