有两种方法可以记录执行的SQl语句:

  • 使用DbContext.Database.Log属性
  • 实现IDbCommandInterceptor接口

一 使用DbContext.Database.Log属性

下面截图显示了Database属性和Log属性,可以看出这个属性是一个委托,类型为Action<string>

对Log属性的解释为:

Set this property to log the SQL generated by the System.Data.Entity.DbContext to the given delegate. For example, to log to the console, set this property to System.Console.Write(System.String).

使用方法:

1)在自定义上下文中获得执行的SQL相关信息,即在自定上下文的构造函数中使用Database.Log

    /// <summary>
/// 自定义上下文
/// </summary>
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class CustomDbContext : DbContext
{
public CustomDbContext()
: base("name=Master")
{ //this.Configuration.LazyLoadingEnabled = false;
//new DropCreateDatabaseIfModelChanges<CustomDbContext>()
//new DropCreateDatabaseAlways<CustomDbContext>()
Database.SetInitializer<CustomDbContext>(null);
this.Database.Log = Log;
} public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
EntityConfiguration.Set(modelBuilder);
} private void Log(string cmd)
{
//或输出到控制台
//Console.Write(cmd); //或输出到文件
//using (StreamWriter sw = new StreamWriter(@"E:\EFCmdLogger.txt"))
//{
// sw.WriteLine(cmd);
//} //或输出到调试信息窗口
Debug.WriteLine(cmd);
}
}

执行结果如下截图

2)在具体的方法中使用

    public class EFOPerations
{ public static void ReadUser()
{
Stopwatch stw = new Stopwatch();
stw.Start();
using (CustomDbContext db = new CustomDbContext())
{
db.Database.Log = Console.WriteLine;
User user = db.Users.Find();
var userDTO = new { Account = user.Account };
}
stw.Stop();
var time = stw.ElapsedMilliseconds;
}
}

注意

db.Database.Log = Console.WriteLine;这条语句的位置;如果将其放到查询语句,即User user = db.Users.Find(1);之后则无法输出信息!

还可以改变日志的格式:

创建继承自DatabaseLogFormatter的类,实现新的格式化器,然后使用

System.Data.Entity.DbConfiguration.SetDatabaseLogFormatter(System.Func<System.Data.Entity.DbContext,System.Action<System.String>,System.Data.Entity.Infrastructure.Interception.DatabaseLogFormatter>)

DatabaseLogFormatter的三个方法

LogCommand:在SQL 语句或存储过程执行前记录它。

LogParameter:记录参数,默认被LogCommand调用(未能验证这一点)

LogResult:记录SQL 语句或存储过程执行后的一些相关信息

这三个方法包含的参数为:

DbCommand command:SQL 语句或存储过程相关的信息。

DbCommandInterceptionContext<TResult> interceptionContext:执行结果相关的信息。

DbParameter parameter:System.Data.Common.DbCommand 的参数。

重写LogCommand或LogResult都可以改变SQL 语句或存储过程相关信息格式,但是注意这两个方法interceptionContext参数的值可能会不一样。

继承DatabaseLogFormatter,实现格式化器

public class CustomDatabaseLogFormatter : DatabaseLogFormatter
{
public CustomDatabaseLogFormatter(DbContext context, Action<string> writeAction)
: base(context, writeAction)
{
}
public override void LogCommand<TResult>(DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{ } public override void LogResult<TResult>(DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
StringBuilder sb = new StringBuilder();
for (int i = ; i < command.Parameters.Count; i++)
{
sb.AppendLine(string.Format("参数名称:{0},值:{1}", command.Parameters[].ParameterName, command.Parameters[].Value));
}
Write(command.CommandText + Environment.NewLine
+ command.CommandTimeout + Environment.NewLine
+ command.CommandType + Environment.NewLine
+ Environment.NewLine
+ sb.ToString());
}
}

设置新的格式化器

public class CustomDbConfiguration : MySqlEFConfiguration
{
public CustomDbConfiguration():base()
{
//this.AddInterceptor(new CommandInterceptor(new Logger()));
SetDatabaseLogFormatter((context, writeAction) => new CustomDatabaseLogFormatter(context, writeAction));
}
}

使用自定义CustomDbConfiguration

[DbConfigurationType(typeof(CustomDbConfiguration))]
public class CustomDbContext : DbContext
{
public CustomDbContext()
: base("name=Master")
{ //this.Configuration.LazyLoadingEnabled = false;
//new DropCreateDatabaseIfModelChanges<CustomDbContext>()
//new DropCreateDatabaseAlways<CustomDbContext>()
Database.SetInitializer<CustomDbContext>(null);
this.Database.Log = Log;
} ...... }

二 实现IDbCommandInterceptor接口

实现IDbCommandInterceptor,同时为了灵活的记录执行信息,定义了日志接口

public class CommandInterceptor : IDbCommandInterceptor
{
private ICommandLogger logger;
public CommandInterceptor(ICommandLogger logger)
{
this.logger = logger;
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
this.logger.Log<int>(command, interceptionContext);
} public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
this.logger.Log<int>(command, interceptionContext);
} public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
this.logger.Log<DbDataReader>(command, interceptionContext);
} public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
this.logger.Log<DbDataReader>(command, interceptionContext);
} public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
this.logger.Log<object>(command, interceptionContext);
} public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
this.logger.Log<object>(command, interceptionContext);
}
} public interface ICommandLogger
{
void Log<T>(DbCommand command, DbCommandInterceptionContext<T> interceptionContext);
} public class Logger : ICommandLogger
{
public void Log<T>(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<T> interceptionContext)
{
StringBuilder sb = new StringBuilder();
for(int i =;i<command.Parameters.Count;i++)
{
sb.AppendLine(string.Format("参数名称:{0},值:{1}", command.Parameters[].ParameterName, command.Parameters[].Value));
} Debug.WriteLine(command.CommandText+Environment.NewLine
+ command.CommandTimeout + Environment.NewLine
+ command.CommandType + Environment.NewLine
+ Environment.NewLine
+ sb.ToString());
}
}

如何使用这两个类呢?

1使用配置文件

<entityFramework>
<interceptors>
<interceptor type="ConsoleApp_EntityFramework.Interceptor.CommandInterceptor, ConsoleApp_EntityFramework.Interceptor">
</interceptor>
</interceptors>
</entityFramework>

但是采用这种方式要对上面的CommandInterceptor 进行改造。

public class CommandInterceptor : IDbCommandInterceptor
{
private ICommandLogger logger;
public CommandInterceptor()
{
this.logger = new Logger();
} ......
}

但是如果EF操作的是Mysql那么这种方法不行,抛出异常:无法识别的元素“interceptors”

2编码方式

只有上面两个类还不够,还要定义创建一个继承自DbConfiguration的配置类

public class CustomDbConfiguration : DbConfiguration
{
public CustomDbConfiguration():base()
{
this.AddInterceptor(new CommandInterceptor(new Logger()));
}
}

在自定义数据库上下文上使用此特性

    /// <summary>
/// 自定义上下文
/// </summary>
[DbConfigurationType(typeof(CustomDbConfiguration))]
public class CustomDbContext : DbContext
{
......
}

一切准备好后运行程序,却抛出异常:

The ADO.NET provider with invariant name 'MySql.Data.MySqlClient' is either not registered in the machine or application config file, or could not be loaded. See the inner exception for details.

似乎是MySql.Data.MySqlClient的问题,其实不是!

如果是SQL Server则没问题,但这里EF框架操作的是MySql,要是使用MySql.Data.Entity.MySqlEFConfiguration这个类,而不是System.Data.Entity.DbConfiguration,所以CustomDbConfiguration应该派生自MySql.Data.Entity.MySqlEFConfiguration

    public class CustomDbConfiguration : MySqlEFConfiguration
{
public CustomDbConfiguration():base()
{
this.AddInterceptor(new CommandInterceptor(new Logger()));
}
.....
}

这样修改后,运行程序得到下面的结果:

可以看到日志打印了两次,这是因为ReaderExecuting和ReaderExecuted各调用了一次,执行的顺序是先ReaderExecuting然后ReaderExecuted。

-----------------------------------------------------------------------------------------

转载与引用请注明出处。

时间仓促,水平有限,如有不当之处,欢迎指正。

Entity Framework——记录执行的命令信息的更多相关文章

  1. [翻译] - <Entity Framework> - 直接执行数据库命令

    原文:[翻译] - <Entity Framework> - 直接执行数据库命令 纯属学习上的记录, 非专业翻译, 如有错误欢迎指正! 原文地址: http://msdn.microsof ...

  2. 关于MySql entity framework 6 执行like查询问题解决方案

    原文:关于MySql entity framework 6 执行like查询问题解决方案 本人不善于言辞,直接开门见山 环境:EF6.0.0.0+MySQL Server5.6+MySqlConnec ...

  3. 在Entity Framework 中执行T-sql语句

    从Entity Framework  4开始在ObjectContext对象上提供了2个方法可以直接执行SQL语句:ExecuteStoreQuery<T> 和 ExecuteStoreC ...

  4. Entity Framework Core 执行SQL语句和存储过程

    无论ORM有多么强大,总会出现一些特殊的情况,它无法满足我们的要求.在这篇文章中,我们介绍几种执行SQL的方法. 表结构 在具体内容开始之前,我们先简单说明一下要使用的表结构. public clas ...

  5. java记录linux top命令信息

    import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.Fi ...

  6. Entity Framework 6 执行Linq to Entities异常"p__linq__1 : String truncation: max=0, len=2, value='测试'"

    场景再现 我需要查询公司名称包含给定字符串的公司,于是我写了下面的测试小例子: var condition = "测试"; var query = from b in db.Com ...

  7. Entity Framework中执行Sql语句

           如果想在EF框架中执行Sql语句,其实很简单,EF里面已经提供了相关的方法(此处使用的EF为EF4.1版本).        EF中提供了两个方法,一个是执行查询的Sql语句SqlQue ...

  8. Entity FrameWork Code First 迁移命令详解

    1. Enable-Migrations 启动迁移 执行get-help Enable-Migrations –detailed 查看Enable-Migrations的详细用法. -ContextT ...

  9. .NET Entity Framework(EF)使用SqlQuery直接操作SQL查询语句或者执行过程

    Entity Framework是微软出品的高级ORM框架,大多数.NET开发者对这个ORM框架应该不会陌生.本文主要罗列在.NET(ASP.NET/WINFORM)应用程序开发中使用Entity F ...

随机推荐

  1. CentOS6.x机器安装Azure CLI2.0【2】

    安装Azure CLI 2.0的前提是:机器中必须有 Python 2.7.x 或 Python 3.x.如果机器中没有其中任何一个Python版本,请及时安装 1.准备一台CentOS 6.9的机器 ...

  2. Django_MTV视图

    WEB服务请求流程? 用户请求通过url,url带着用户的用户信息封装成request,然后服务器收到url请求,激活获取url中带来的request,服务器处理request逻辑后,返回封装好的re ...

  3. junit4X系列--Builder、Request与JUnitCore

    原文出处:http://www.blogjava.net/DLevin/archive/2012/05/12/377957.html.感谢作者的无私分享. 初次用文字的方式记录读源码的过程,不知道怎么 ...

  4. linkin大话面向对象--GC和jar包

    GC java的垃圾回机制是java语言的重要机制之一.当程序创建对象,数组等引用类型实体时,系统都会在堆内存中为之分配一块内存区,对象就保存在这块内存区中.当这块内存不再被任何变量引用时,这块内存就 ...

  5. 【转载】Linux时间相关结构与函数

    1 时间的获取 在程序当中, 我们经常要输出系统当前的时间,比如日志文件中的每一个事件都要记录其产生时间.在 C 语言中获取当前时间的方法有以下几种,它们所获得的时间精度从秒级到纳秒,各有所不同. 表 ...

  6. 【转】sed正则表达式

    1 正则表达式简介 正则表达式(Regular Expression) 是一种描述文本(或字符串)模式的工具.正则表达式常用于查找文本的场合.想想一下我们日常生活中的例子,假如你想从电话本里找一个联系 ...

  7. 使用CefSharp开发一个12306“安心刷票弹窗通知”工具

    有需求就要改进 最近两年没有在春节回家过年了,主要是票太难买,虽然之前写了一个12306“无声购票弹窗”工具,解决了抢票问题,但是全家老小一起回去还是很累,干脆就在北京过年了.这两天突然有一个朋友问我 ...

  8. windows程序设计获取文本框(窗口、对话框)文本

    就是这样一个简单的界面,窗口上重绘的对话框(这种写法参考我之前博文): 需要做到的就是点击确定,获取文本框中内容. // 处理对话框消息 INT_PTR CALLBACK NewDlgProc(HWN ...

  9. 夏令营讲课内容整理 Day 4.

    本日主要内容就是搜索(打暴力 搜索可以说是OIer必会的算法,同时也是OI系列赛事常考的算法之一. 有很多的题目都可以通过暴力搜索拿到部分分,而在暴力搜索的基础上再加一些剪枝优化, 就有可能会拿到更多 ...

  10. js实现点击切换显示隐藏,点击其它位置再隐藏

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...