.net core实用技巧——将EF Core生成的SQL语句显示在控制台中

前言

笔者最近在开发和维护一个.NET Core项目,其中使用几个非常有意思的.NET Core相关的扩展,在此总结整理一下。

EF Core性能调优

如果你的项目中使用了EF Core, 且正在处于性能调优阶段,那么了解EF Core生成的SQL语句是非常关键的。那么除了使用第三方工具,如何查看EF Core生成的SQL语句呢?这里笔者将给出一个基于.NET Core内置日志组件的实现方式。

创建一个实例项目

我们首先建一个控制台程序,在主程序中我们编写了一个最简单的EF查询。

  class Program {
    static void Main (string[] args) {

      var dbOptionBuilder = new DbContextOptionsBuilder<MyDbContext>();
      dbOptionBuilder
       .UseMySql("server=localhost;port=3306;database=EFCoreSampleDB;userid=root;pwd=a@12345");

      using (var dbContext = new MyDbContext(dbOptionBuilder.Options)) {
        var query = dbContext.Users.ToList();
      }
    }
  }

这里为了演示,我们提前创建了一个MySql数据库,并在项目中创建了一个对应的EF Core上下文。当前上下文中只有一个User实体,该实体只有2个属性UserId和UserName。

  public class MyDbContext : DbContext {

    public MyDbContext (DbContextOptions<MyDbContext> options) : base (options) {

    }

    public DbSet<User> Users { get; set; }
  }
  public class User
  {
    [Key]
    public Guid UserId { get; set;}
    public string UserName { get; set;}
  }

如何生成的SQL语句输出到控制台?

.NET Core中提供了非常完善的日志接口。这里为了和.NET Core的日志接口集成,我们需要实现2个接口,一个是日志提供器接口ILoggerProvider, 一个是日志接口ILogger

EFLoggerProvider.cs

  public class EFLoggerProvider : ILoggerProvider {
    public ILogger CreateLogger (string categoryName) => new EFLogger (categoryName);
    public void Dispose () { }
  }

EFLoggerProvider的代码非常的简单,就是直接返回一个我们后续创建的EFLogger对象。

EFLogger.cs

	public class EFLogger : ILogger {
    private readonly string categoryName;

    public EFLogger (string categoryName) => this.categoryName = categoryName;

    public bool IsEnabled (LogLevel logLevel) => true;

    public void Log<TState> (LogLevel logLevel,
      EventId eventId,
      TState state,
      Exception exception,
      Func<TState, Exception, string> formatter) {
        var logContent = formatter (state, exception);
        Console.WriteLine ();
        Console.WriteLine (logContent);
      }
    }

    public IDisposable BeginScope<TState> (TState state) => null;
  }

这里我们主要使用了内置的formatter格式化了日志信息。

最后我们还需要将自定义的日志处理类和EF Core集成起来。这里我们需要复写上下文类的OnConfiguring方法。在其中通过UseLoggerFactory方法,将我们自定义的日志处理类和EF Core的日志系统关联起来。

	public class MyDbContext : DbContext {

    public MyDbContext (DbContextOptions<MyDbContext> options) : base (options) {

    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {

      var loggerFactory = new LoggerFactory ();
      loggerFactory.AddProvider(new EFLoggerProvider());
      optionsBuilder.UseLoggerFactory(loggerFactory);

      base.OnConfiguring(optionsBuilder);
    }

    public DbSet<User> Users { get; set; }
  }

下面我们启动项目,看一下效果。这里日志信息正确的显示出来了。

PS: 如果项目中使用了通用主机或者ASP.NET Core, 你也可以在服务配置部分,通过DbContextOptions参数配置。

services.AddDbContext<MyDbContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("MyDb"))
          .UseLoggerFactory(new LoggerFactory()));

如何去除无关日志?

在前面的步骤中,我们成功的输出了查询语句,但是有一个问题是我们只想查看输出的SQL语句,其他的信息我们都不想要,那么能不能去除掉这些无关日志呢?答案是肯定的。

我们可以在Log方法中,通过分类名称,只输出Microsoft.EntityFrameworkCore.Database.Command分类下的日志,该日志即生成的SQL语句部分。

   public void Log<TState> (LogLevel logLevel,
 		EventId eventId,
 		TState state,
 		Exception exception,
 		Func<TState, Exception, string> formatter)
  {

    if (categoryName == DbLoggerCategory.Database.Command.Name &&
      logLevel == LogLevel.Information) {
      var logContent = formatter (state, exception);

      Console.WriteLine ();
      Console.ForegroundColor = ConsoleColor.Green;
      Console.WriteLine (logContent);
      Console.ResetColor ();
    }
  }

这里我们也做了一些其他的操作,通过修改控制台输出文本的颜色,高亮了生成的SQL语句。重新启动项目之后,效果如下。

如何显示敏感数据?

这里看似我们已经完成了EF Core的语句输出,但是在实际使用中,你还会遇到另外一个问题。

下面我们修改一下我们的主程序,我们尝试插入一条User信息。

  class Program {
    static void Main (string[] args) {

      var dbOptionBuilder = new DbContextOptionsBuilder<MyDbContext> ();
      dbOptionBuilder.UseMySql ("server=localhost;port=3306;database=EFCoreSampleDB;userid=root;pwd=a@12345");

      using (var dbContext = new MyDbContext (dbOptionBuilder.Options)) {
        dbContext.Users.Add(new User { UserId = Guid.NewGuid(), UserName = "Lamond Lu"});
        dbContext.SaveChanges();
      }
    }
  }

重新运行程序,你会得到一下结果。

这里你可能会问为什么不显示@p0, @p1参数的值。这里是原因是为了保护敏感数据,EF Core默认关闭的敏感数据的显示配置,如果你想要查看敏感数据,你需要通过DbContextOptionsBuilder对象的EnableSensitiveDataLogging方法修改敏感数据日志配置。

  protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder) {
    var loggerFactory = new LoggerFactory ();
    loggerFactory.AddProvider (new EFLoggerProvider ());
    optionsBuilder.EnableSensitiveDataLogging (true);
    optionsBuilder.UseLoggerFactory (loggerFactory);

    base.OnConfiguring (optionsBuilder);
  }

重新启动项目之后,你就能看到@p0, @p1参数的值了。

以上就是.net core实用技巧——将EF Core生成的SQL语句显示在控制台中的详细内容,更多关于.net core实用技巧的资料请关注我们其它相关文章!

(0)

相关推荐

  • 在.NET Core类库中使用EF Core迁移数据库到SQL Server的方法

    前言 如果大家刚使用EntityFramework Core作为ORM框架的话,想必都会遇到数据库迁移的一些问题. 起初我是在ASP.NET Core的Web项目中进行的,但后来发现放在此处并不是很合理,一些关于数据库的迁移,比如新增表,字段,修改字段类型等等,不应该和最上层的Web项目所关联,数据的迁移文件放到这里也感觉有点多余,有点乱乱的感觉,所以才想着单独出来由专门的项目进行管理会比较好,也比较清晰! 注意目标框架选择的是.NET Core 2.0而不是.NET Standard 2.0.

  • .NET Core类库System.Reflection.DispatchProxy实现简易Aop的方法

    前言 aop即是面向切面编程,众多Aop框架里Castle是最为人所知的,另外还有死去的Spring.NET,当然,.NET Core社区新秀AspectCore在性能与功能上都非常优秀,已经逐渐被社区推崇和有越来越多的人使用.感谢柠檬同学的礼物! 如果大家出于自身需求或者学习,想实现一个Aop,是不是觉得一来就要使用Emit去做?最近我了解到了System.Reflection.DispatchProxy这个corefx类库,已经实现了动态代理功能. 1|1System.Reflection.

  • CodeFirst从零开始搭建Asp.Net Core2.0网站

    一步步教大家如何搭建Asp.Net Core2.0网站,以下所有都是建立在.NETCore2.0环境已经搭建好 右键解决方案>新建项目> 选择Web>ASP.NETCoreWeb应用程序(.NET Core) 选择Web应用程序,暂时不选择启用Docker,身份验证选择个人用户账户(会自动生成一系列和用户认证的代码) 随后生代码层次目录如下: 其中会包含身份信息的相关实现,比如相关实体信息(user)之类的,如果想对扩展微软自动的生成的用户实体类,可在Models中的Applicatio

  • .net core EF Core调用存储过程的方式

    前言 在这里,我们将尝试去学习一下 .net core EF Core 中调用存储过程. 我们知道,EF Core 是不支持直接调用存储过程的,那它又提供了什么样的方式去执行存储过程呢?有如下方法: 1.FromSql,官方文档 DbSet<TEntity>.FromSql() 2.执行SQl命令 DbContext.Database.ExecuteSqlCommand() 但是,这两种方式都有局限性: 1.FromSql方式的结果一定要是实体类型,就是数据库表映射的模型.这意味着,执行存储过

  • 详解.Net Core 权限验证与授权(AuthorizeFilter、ActionFilterAttribute)

    在.Net Core 中使用AuthorizeFilter或者ActionFilterAttribute来实现登录权限验证和授权 一.AuthorizeFilter 新建授权类AllowAnonymous继承AuthorizeFilter,IAllowAnonymousFilter public class AllowAnonymous : AuthorizeFilter, IAllowAnonymousFilter { } 新建拦截类继承AuthorizeFilter public class

  • .Net Core中使用ref和Span<T>提高程序性能的实现代码

    一.前言 其实说到ref,很多同学对它已经有所了解,ref是C# 7.0的一个语言特性,它为开发人员提供了返回本地变量引用和值引用的机制. Span也是建立在ref语法基础上的一个复杂的数据类型,在文章的后半部分,我会有一个例子说明如何使用它. 二.ref关键字 不论是ref还是out关键,都是一种比较难以理解和操作的语言特性,如C语言中操作指针一样,这样的高级语法总是什么带来一些副作用,但是我不认为这有什么,而且不是每一个C#开发者都要对这些内部运行的机制有着深刻的理解,我觉得不论什么复杂的东

  • .net EF Core专题:EF Core 读取数据时发生了什么?

    原文:https://bit.ly/2UMiDLb 作者:Jon P Smith 翻译:王亮 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的.其中可能会去除一些本人实在不知道如何组织但又不影响理解的句子. 本文将为你详细描绘 EF Core 从数据库中读取数据的"幕后"视图.我将揭开两种数据库读取方式的面纱:一个是普通的查询,另一个是使用 AsNoTracking 方法的非跟踪查询.我还将通过一个实验来演示我是如何解决我的一个客户遇到的性能问题. 我假设你对 EF C

  • .net core实用技巧——将EF Core生成的SQL语句显示在控制台中

    前言 笔者最近在开发和维护一个.NET Core项目,其中使用几个非常有意思的.NET Core相关的扩展,在此总结整理一下. EF Core性能调优 如果你的项目中使用了EF Core, 且正在处于性能调优阶段,那么了解EF Core生成的SQL语句是非常关键的.那么除了使用第三方工具,如何查看EF Core生成的SQL语句呢?这里笔者将给出一个基于.NET Core内置日志组件的实现方式. 创建一个实例项目 我们首先建一个控制台程序,在主程序中我们编写了一个最简单的EF查询. class P

  • mybatis 对于生成的sql语句 自动加上单引号的情况详解

    目录 对于生成的sql语句 自动加上单引号的情况 mySQL中replace的用法 mybatis中IFNULL(P1,P2)函数的用法 mybatis单引号字母逻辑处理的一个坑 原因分析 对于生成的sql语句 自动加上单引号的情况 mybatis是这样的,如果表的字段跟系统字段冲突,写sql语句的时候必须得加上单引号,这样才会区分 mySQL中replace的用法 1.replace into replace into table (id,name) values('1','aa'),('2'

  • .Net core下直接执行SQL语句并生成DataTable的实现方法

    .net core可以执行SQL语句,但是只能生成强类型的返回结果.例如var blogs = context.Blogs.FromSql("SELECT * FROM dbo.Blogs").ToList().而不允许返回DataSet.DataTable等弱类型.可能由于这个原因没有实现在.net core中DataTable,然而DataTable还是可能会用到的.我们这里就有一个数据仓库的需求,允许用户自行编写类似SQL语句,然后执行,以表格展示.因为语句是千变万化的,因此我也

  • ASP.NET 5已终结,迎来ASP.NET Core 1.0和.NET Core 1.0

    ASP.NET 在过去的 15 年里是个非常不错的"品牌". ASP.NET 4.6 已经支持在生产环境使用:http://get.asp.net. 但是,命名是新的,完全截取自 ASP.NET 框架 -- "ASP.NET 5",但这并不是个好主意,其中一个原因是:5 > 4.6,这样看起来 ASP.NET 5 比 ASP.NET 4.6 版本号更大,更好,甚至是可以替代 ASP.NET 4.6. 所以修改了名字,选择了一个更好的版本号. 重新引入 ASP.

  • Java反射 JavaBean对象自动生成插入,更新,删除,查询sql语句操作

    通过反射根据提供的表名.POJO类型.数据对象自动生成sql语句. 如名为 User 的JavaBean与名为 user 的数据库表对应,可以提供一个封装有数据的User对象user,根据user中含有的数据自动生成sql语句. 1.生成插入语句(插入user中包含的非空数据的语句): String insertSql = getInsertSql("user", User.class, user); 2.生成更新语句(user中id不能为空): String updateSql =

  • 仿orm自动生成分页SQL分享

    先看看目前这4种数据库的分页写法: 复制代码 代码如下: -- OracleSELECT * FROM (     SELECT ROWNUM RN,  PageTab.* FROM                  (                 SELECT * FROM User_Tables order by id desc                 ) PageTab  where ROWNUM <= 3010             ) Where RN>= 3001 -

  • Mybatis基于注解形式的sql语句生成实例代码

    对其做了些优化,但此种sql生成方式仅适用于复杂程度不高的sql,所以实用性不是很高,仅仅是写着玩的,知道点mybatis的注解形式的使用方式,可能以后会逐渐完善起来.第一次写博客,写的简单点. package com.bob.config.mvc.mybatis; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retenti

  • 利用Python脚本批量生成SQL语句

    通过Python脚本批量生成插入数据的SQL语句 原始SQL语句: INSERT INTO system_user (id, login_name, name, password, salt, code, createtime, email, main_org, positions, status, used, url, invalid, millis, id_card, phone_no, past, end_date, start_date) VALUES ('6', 'db', 'db',

随机推荐