Entity Framework——记录执行的命令信息
有两种方法可以记录执行的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——记录执行的命令信息的更多相关文章
- [翻译] - <Entity Framework> - 直接执行数据库命令
原文:[翻译] - <Entity Framework> - 直接执行数据库命令 纯属学习上的记录, 非专业翻译, 如有错误欢迎指正! 原文地址: http://msdn.microsof ...
- 关于MySql entity framework 6 执行like查询问题解决方案
原文:关于MySql entity framework 6 执行like查询问题解决方案 本人不善于言辞,直接开门见山 环境:EF6.0.0.0+MySQL Server5.6+MySqlConnec ...
- 在Entity Framework 中执行T-sql语句
从Entity Framework 4开始在ObjectContext对象上提供了2个方法可以直接执行SQL语句:ExecuteStoreQuery<T> 和 ExecuteStoreC ...
- Entity Framework Core 执行SQL语句和存储过程
无论ORM有多么强大,总会出现一些特殊的情况,它无法满足我们的要求.在这篇文章中,我们介绍几种执行SQL的方法. 表结构 在具体内容开始之前,我们先简单说明一下要使用的表结构. public clas ...
- java记录linux top命令信息
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.Fi ...
- 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 ...
- Entity Framework中执行Sql语句
如果想在EF框架中执行Sql语句,其实很简单,EF里面已经提供了相关的方法(此处使用的EF为EF4.1版本). EF中提供了两个方法,一个是执行查询的Sql语句SqlQue ...
- Entity FrameWork Code First 迁移命令详解
1. Enable-Migrations 启动迁移 执行get-help Enable-Migrations –detailed 查看Enable-Migrations的详细用法. -ContextT ...
- .NET Entity Framework(EF)使用SqlQuery直接操作SQL查询语句或者执行过程
Entity Framework是微软出品的高级ORM框架,大多数.NET开发者对这个ORM框架应该不会陌生.本文主要罗列在.NET(ASP.NET/WINFORM)应用程序开发中使用Entity F ...
随机推荐
- Java中的SerialVersionUID
Java中的SerialVersionUID 序列化及SergalVersionUID困扰着许多Java开发人员.我经常会看到这样的问题,什么是SerialVersionUID,如果实现了Serial ...
- 03 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之web层
Github:https://github.com/nnngu 项目源代码:https://github.com/nnngu/nguSeckill 前端交互流程设计 对于一个系统,需要产品经理.前端工 ...
- ASP.net core 2.0.0 中 asp.net identity 2.0.0 的基本使用(一)—修改数据库连接
开发环境:vs2017 版本:15.3.5 项目环境:.net framework 4.6.1 模板asp.net core 2.0 Web应用程序(模型视图控制器) 身份验证:个人用户账号 ...
- linux_目录结构
目录的作用是什么? 1. 归档和分类 2. 区分同名文件 什么是FHS? 目录层次标准,linux目录规范标准 linux系统目录有哪些特点? 1. 逻辑上所有目录都在 / 目录下,根目录是所有目录的 ...
- [搬运] .NET Core 2.1中改进的堆栈信息
原文 : Stacktrace improvements in .NET Core 2.1 作者 : Ben Adams 译者 : 张很水 . NET Core 2.1 现在具有可读的异步堆栈信息!使 ...
- freemarker常用值格式化方法
freemarker常用的值格式化方法: 1.${price?string('0.00')} 对price进行格式化,小数点后不足2位用0补足. 比如:price=1 输出:1.00 2.${pric ...
- Java Cookie和Session
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- zabbix图形乱码
毕竟是中文为主,特别是有些香项目最好以中文命名,容易区分,也方便识别 环境: centos7.3安装zabbix3.2 问题: 图文乱码问题 原理上只要找到对应的字符集,在修改配置文件 windows ...
- 【转】对GAMIT/GLOBK的基本认识
1.1 GAMIT/GLOBK软件可从网络上申请下载.该软件功能强大,用途广泛,一般包括精确定位,大气层可降水汽估计和空间电离层变化分析等.后两种用途只需要用到GAMIT模块,精确定位则还需要GL ...
- VS下WPF自定义控件的基本步骤和基本代码实现
一.自定义控件的基本步骤: (本示例项目名称为:W:添加的自定义控件名称为) 1. 在"解决方案资源管理器"窗口的项目名上: 右击à添加à新建项(Ctrl+Shift+A) 2. ...