Entity Framework——记录执行的命令信息

时间:2022-10-09 15:17:43

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

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

一 使用DbContext.Database.Log属性

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

Entity Framework——记录执行的命令信息

Entity Framework——记录执行的命令信息

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

执行结果如下截图

Entity Framework——记录执行的命令信息

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

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

Entity Framework——记录执行的命令信息

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

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

转载与引用请注明出处。

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

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

  1. &lbrack;翻译&rsqb; - &lt&semi;Entity Framework&gt&semi; - 直接执行数据库命令

    原文:[翻译] - <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异常&quot&semi;p&lowbar;&lowbar;linq&lowbar;&lowbar;1 &colon; String truncation&colon; max&equals;0&comma; len&equals;2&comma; value&equals;&&num;39&semi;测试&&num;39&semi;&quot&semi;

    场景再现 我需要查询公司名称包含给定字符串的公司,于是我写了下面的测试小例子: 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. &period;NET Entity Framework&lpar;EF&rpar;使用SqlQuery直接操作SQL查询语句或者执行过程

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

随机推荐

  1. 【Java EE 学习 72 下】【数据采集系统第四天】【移动&sol;复制页分析】【使用串行化技术实现深度复制】

    一.移动.复制页的逻辑实现 移动.复制页的功能是在设计调查页面的时候需要实现的功能.规则是如果在同一个调查中的话就是移动,如果是在不同调查中的就是复制. 无论是移动还是复制,都需要注意一个问题,那就是 ...

  2. Oracle系列——开发中奇葩问题你遇到几个(一)

    前言:在使用oracle数据进行开发的时候有没有经常出现一些很奇怪.很纳闷.很无厘头的问题呢.下面是本人使用oracle一段时间遇到的问题小节,在此做个记录,方便以后再遇到类似的问题能快速解决.如果你 ...

  3. href脱离iframe显示

    iframe框架页面如下: <!DOCTYPE html><html lang="zh"><head><meta name='viewpo ...

  4. Python科学画图小结

    Python画图主要用到matplotlib这个库.具体来说是pylab和pyplot这两个子库.这两个库可以满足基本的画图需求,而条形图,散点图等特殊图,下面再单独具体介绍. 首先给出pylab神器 ...

  5. Spring框架学习之第2节

    传统的方法和使用spring的方法 使用spring,没有new对象,我们把创建对象的任务交给了spring的框架,通过配置用时get一下就行. 项目结构 applicationContext.xml ...

  6. &lbrack;Everyday Mathematic&rsqb;20150216

    设 $A,B,C$ 是同阶方阵, 试证: $$\bex (A-B)C=BA^{-1}\ra C(A-B)=A^{-1}B. \eex$$

  7. JS中的this 指向问题

    我发现在对JS的学习中有很多朋友对this的指向问题还是有很大的误区或者说只是大致了解,但是一旦遇到复杂的情况就会因为this指向问题而引发各种bug. 对于之前学习过c或者是Java的朋友来说可能这 ...

  8. unittest同时支持参数化和生成html报告

    最近在用python3.6+unittest+requests做自动化接口测试.发现一个问题,unittest中使用第3方插件parameterized进行参数化,再生成html报告时,运行就会失败. ...

  9. &num;C&plus;&plus;初学记录(算法2)

    A - Game 23 Polycarp plays "Game 23". Initially he has a number n and his goal is to trans ...

  10. &lbrack;js高手之路&rsqb;Node&period;js实现简易的爬虫-抓取博客所有文章列表信息

    抓取目标:就是我自己的博客:http://www.cnblogs.com/ghostwu/ 需要实现的功能: 抓取博客所有的文章标题,超链接,文章摘要,发布时间 需要用到的库: node.js自带的h ...