.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 个属性UserIdUserName

    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 == "Microsoft.EntityFrameworkCore.Database.Command" &&            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 参数的值了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值