Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Entity Framework——记录执行的命令信息

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

作者头像
甜橙很酸
发布于 2018-03-30 02:16:25
发布于 2018-03-30 02:16:25
1.1K00
代码可运行
举报
文章被收录于专栏:DOTNETDOTNET
运行总次数:0
代码可运行

有两种方法可以记录执行的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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /// <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)在具体的方法中使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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(1);
                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,实现格式化器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 = 0; i < command.Parameters.Count; i++)
            {
                sb.AppendLine(string.Format("参数名称:{0},值:{1}", command.Parameters[0].ParameterName, command.Parameters[0].Value));
            }
            Write(command.CommandText + Environment.NewLine
                + command.CommandTimeout + Environment.NewLine
                + command.CommandType + Environment.NewLine
                + Environment.NewLine
                + sb.ToString());
        }
}

设置新的格式化器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CustomDbConfiguration : MySqlEFConfiguration
    {
        public CustomDbConfiguration():base()
        {
            //this.AddInterceptor(new CommandInterceptor(new Logger()));
            SetDatabaseLogFormatter((context, writeAction) => new CustomDatabaseLogFormatter(context, writeAction));
        }
}

使用自定义CustomDbConfiguration

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[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,同时为了灵活的记录执行信息,定义了日志接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 =0;i<command.Parameters.Count;i++)
            {
                sb.AppendLine(string.Format("参数名称:{0},值:{1}", command.Parameters[0].ParameterName, command.Parameters[0].Value));
            }
            
            Debug.WriteLine(command.CommandText+Environment.NewLine
                + command.CommandTimeout + Environment.NewLine
                + command.CommandType + Environment.NewLine
                + Environment.NewLine
                + sb.ToString());
        }
    }

如何使用这两个类呢?

1使用配置文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<entityFramework>
    <interceptors>
      <interceptor type="ConsoleApp_EntityFramework.Interceptor.CommandInterceptor, ConsoleApp_EntityFramework.Interceptor">
      </interceptor>
    </interceptors>
 </entityFramework>

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CommandInterceptor : IDbCommandInterceptor
    {
        private ICommandLogger logger;
        public CommandInterceptor()
        {
            this.logger = new Logger();
        }

    ......
}

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

2编码方式

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CustomDbConfiguration : DbConfiguration
    {
        public CustomDbConfiguration():base()
        {
            this.AddInterceptor(new CommandInterceptor(new Logger()));
        }
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /// <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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public class CustomDbConfiguration : MySqlEFConfiguration
    {
        public CustomDbConfiguration():base()
        {
            this.AddInterceptor(new CommandInterceptor(new Logger()));
        }
        .....
    }

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

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

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

转载与引用请注明出处。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ef和mysql使用(二)--让mysql支持EntityFramework.Extended实现批量更新和删除
我们都知道Entity Framework 中不能同时更新多条记录,但是一个老外写的扩展库可以实现此功能EntityFramework.Extended,但是如何是mysql数据库要怎么实现呢
yaphetsfang
2020/07/30
1.4K0
EntityFramework的多种记录日志方式,记录错误并分析执行时间过长原因(系列4)
本文通过介绍Entity Framework的日志记录功能,讲解了在.NET中如何实现数据库操作记录的解决方案。通过使用Entity Framework的上下文、数据库日志和IDbCommandInterceptor接口,开发者可以记录数据库操作,包括查询、更新和删除等,并获取操作的时间、SQL语句、参数等信息。同时,文章还提供了数据库日志记录的具体实现代码和示例,帮助读者更好地理解实现过程。通过本文的学习,读者可以掌握如何在.NET中实现对数据库操作的记录和跟踪,提高数据库应用的稳定性和可维护性。
GuZhenYin
2018/01/04
8750
EntityFramework的多种记录日志方式,记录错误并分析执行时间过长原因(系列4)
EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录
一晃又大半年没更新技术博客..唉,去年一年发生了太多事情..博主真的 一言难尽..
GuZhenYin
2021/03/18
1.1K0
EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录
Entity Framework 小知识(二)
接下来使用 DbConfigurationType 属性在上下文类中设置基于代码的配置类:
喵叔
2020/09/08
5880
Mysql 该如何 Entity Framework 数据库迁移 和 如何更好的支持EF.Extended
问题 1.在使用EntityFramework访问Mysql的时候,使用迁移来生成数据库或者更新数据库时候会遇到一些问题 2.EntityFramework.Extended对Mysql的支持不是很完全,其中修改是无法直接使用的需要做一些处理 3.EntityFramework.Extended如何跟EntityFramework其他的操作在一个事物里面(针对网友zengfanlin 问题) 解决方案 1.首先解决第一个问题 准备条件:用Nuget下载Mysql.Data.Entity(可以将依赖连同下载)
逸鹏
2018/04/11
1.8K0
Mysql 该如何 Entity Framework 数据库迁移 和 如何更好的支持EF.Extended
Entity Framework 简单查询
第一步还是先建立一个控制台的应用程序,然后通过Nuget添加Entity Framework。那么同时会给packages.config和App.config添加相应的配置。
aehyok
2018/09/11
8850
Entity Framework 简单查询
Entity Framework 自动生成CodeFirst代码
在前面的文章中我们提到Entity Framework的“Code First”模式也同样可以基于现有数据库进行开发。今天就让我们一起看一下使用Entity Framework Power Tools如何基于现有数据库生成数据类和数据库上下等。
aehyok
2018/09/11
8670
Entity Framework 自动生成CodeFirst代码
.NET:Entity Framework 笔记
有二年没关注EF,今天无意试了下发现跟主流的Hibernate等ORM框架越来越接近了,先看下Entity类的定义: using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EFSample.Model { [Table("T_ORDER")]
菩提树下的杨过
2018/01/19
1.1K0
.NET EF Core(Entity Framework Core)
1、Entity Framework Core(EF Core)是微软官方的ORM框架。优点:功能强大、官方支持、生产效率高、力求屏蔽底层数据库差异;缺点:复杂、上手门槛高、不熟悉EFCore的话可能会进坑。 2、Dapper。优点:简单,N分钟即可上手,行为可预期性强;缺点:生产效率低,需要处理底层数据库差异。 3、EF Core是 模型驱动 (Model-Driven)的开发思想,Dapper是 数据库驱动(DataBase-Driven)的开发思想的。没有优劣,只有比较。 4、性能: Dapper等≠性能高;EF Core≠性能差。 5、EF Core是官方推荐、推进的框架,尽量屏蔽底层数据库差异,.NET开发者必须熟悉,根据的项目情况再决定用哪个。
鱼找水需要时间
2024/03/23
1K0
.NET EF Core(Entity Framework Core)
Entity Framework——配置文件设置
可以使用配置文件或代码(EF6起)配置EF框架。 一、使用配置文件 安装Entity Framework自动生成的配置 当使用VS的NuGet自动安装Entity Framework(本文使用6.2.
甜橙很酸
2018/03/30
1.5K0
ADO.NET Entity Framework CodeFirst 如何输出日志(EF 5.0)
ADO.NET Entity Framework CodeFirst 如何输出日志(EF4.3) 用的EFProviderWrappers ,这个组件好久没有更新了,对于SQL执行日志的解决方案的需求
张善友
2018/01/29
6160
ADO.NET Entity Framework CodeFirst 如何输出日志(EF 5.0)
Entity Framework CodeFirst尝试
Code First模式我们称之为“代码优先”模式,是从EF4.1开始新建加入的功能。使用Code First模式进行EF开发时开发人员只需要编写对应的数据类(其实就是领域模型的实现过程),然后自动生成数据库。这样设计的好处在于我们可以针对概念模型进行所有数据操作而不必关系数据的存储关系,使我们可以更加自然的采用面向对象的方式进行面向数据的应用程序开发。
aehyok
2018/09/11
7130
Entity Framework CodeFirst尝试
Entity Framework——读写分离
1 实现 CustomDbContext扩展了DbContext,其构造函数带有形式参nameOrConnectionString,可以在使用CustomDbContext时指定数据库连接字符串。 DbContextFactory包含两个属性MasterDbContext和SlaveDbContext,MasterDbContext为主库上下文,SlaveDbContext为从库上下文。DbContextFactory还包含了一个方法:UpdateSlaves用于实现对SlaveDbContext的更新,因
甜橙很酸
2018/03/08
1.1K0
【源码解读(一)】EFCORE源码解读之创建DBContext查询拦截
    在网上很少看到有关于系统讲解EFCore源码的,可能大概也许是因为EFCore的源码总体是没有asp.net web的源码流程清晰,正如群友所说,EFCore的源码大致看起来有点凌乱,与其说凌乱,不如说是没有一个好的方向;然后昨天在群里有一个朋友再说,EfCore的拦截器如何注入Web的服务,以及EfCore如何自定义查询,我就看了一下EfCore的源码,在此之前我针对asp.net web 做了一个源码解读,有兴趣的朋友可以看前面的文章,也给别人说过啥时候讲解一下efcore的源码,刚好借助这么一个机会,讲一讲EfCore的源码,本篇文章作为一个开端,会呈现一下几点
陈显达
2023/10/16
1.1K0
【源码解读(一)】EFCORE源码解读之创建DBContext查询拦截
Entity Framework——常见报错总结
1 实体属性配置为IsRequired()对更新的影响 抛出异常类型DbEntityValidationException 表结构: 实体: public class User {
甜橙很酸
2018/03/08
8180
Entity Framework——常见报错总结
Entity Framework 小知识(三)
在单服务器上运行的站点,为了防止出现脏读现象,我们一般使用Lock语句关键字,但是如果在分布式站点上使用Lock语句关键字是不起作用的,因为程序锁住了服务器1数据库实例,但服务器2并不知道服务器1已被锁住,这样依然会出现脏读现象。这时我们就用到了EF的乐观并发。
喵叔
2020/09/08
3000
entity framework数据库映射(ORM)
Sql Server安装:EntityFramework Mysql安装:MySql.Data.Entity
sofu456
2022/05/06
1.1K0
entity framework数据库映射(ORM)
浅析Entity Framework Core中的并发处理
本文讲述如何使用Entity Framework Core来实现一个乐观并发控制,并介绍在.NET Core中使用DbContext进行数据库操作时的一些常见问题和解决方案。
GuZhenYin
2018/01/04
2.9K0
浅析Entity Framework Core中的并发处理
asp.net mvc entityframework sql server 迁移至 mysql方法以及遇到的问题
我原来的项目是asp.net mvc5 + entityframework 6.4 for sql server(localdb,sql server),现在需要把数据库切换成mysql,理论上entityframework是可以完全做到无缝切换,毕竟ORM的设计就是为了兼容不同的底层数据库。
阿新
2020/05/12
1.4K0
Entity Framework——并发策略
使用EF框架遇到并发时,一般采取乐观并发控制。 1支持并发检验 为支持并发检验,需要对实体进行额外的设置。默认情况下是不支持并发检验的。有以下两种方式: 方式名称 说明 时间戳注解/行版本 使用TimestampAttribute特性,实体的属性必须是byte数组类型 非时间戳注解 使用ConcurrencyCheckAttribute Fluent API 使用StringPropertyConfiguration.IsConcurrencyT
甜橙很酸
2018/04/17
1.2K0
推荐阅读
相关推荐
ef和mysql使用(二)--让mysql支持EntityFramework.Extended实现批量更新和删除
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验