.NET Core实用技巧 如何将EF Core生成的SQL语句显示在控制台中

  • A+
所属分类:.NetCore

.NET Core实用技巧 如何将EF Core生成的SQL语句显示在控制台中

EF Core性能调优

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

创建一个实例项目

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

  1. class Program {  
  2.         static void Main (string[] args) {  
  3.   
  4.             var dbOptionBuilder = new DbContextOptionsBuilder<MyDbContext>();  
  5.             dbOptionBuilder  
  6.              .UseMySql("server=localhost;port=3306;database=EFCoreSampleDB;userid=root;pwd=a@12345");  
  7.   
  8.             using (var dbContext = new MyDbContext(dbOptionBuilder.Options)) {  
  9.                 var query = dbContext.Users.ToList();  
  10.             }  
  11.         }  
  12.     }  

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

  1. public class MyDbContext : DbContext {  
  2.   
  3.         public MyDbContext (DbContextOptions<MyDbContext> options) : base (options) {  
  4.   
  5.         }  
  6.   
  7.         public DbSet<User> Users { getset; }  
  8.     }  
  1. public class User  
  2.   {  
  3.       [Key]  
  4.       public Guid UserId { getset;}  
  5.       public string UserName { getset;}  
  6.   }  

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

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

EFLoggerProvider.cs

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

EFLogger.cs

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

  1. public class EFLogger : ILogger {  
  2.         private readonly string categoryName;  
  3.   
  4.         public EFLogger (string categoryName) => this.categoryName = categoryName;  
  5.   
  6.         public bool IsEnabled (LogLevel logLevel) => true;  
  7.   
  8.         public void Log<TState> (LogLevel logLevel,   
  9.             EventId eventId,  
  10.             TState state,   
  11.             Exception exception,   
  12.             Func<TState, Exception, string> formatter) {  
  13.                 var logContent = formatter (state, exception);  
  14.                 Console.WriteLine ();  
  15.                 Console.WriteLine (logContent);  
  16.             }  
  17.         }  
  18.   
  19.         public IDisposable BeginScope<TState> (TState state) => null;  
  20.     }  

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

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

  1. public class MyDbContext : DbContext {  
  2.   
  3.         public MyDbContext (DbContextOptions<MyDbContext> options) : base (options) {  
  4.   
  5.         }  
  6.   
  7.         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {  
  8.   
  9.             var loggerFactory = new LoggerFactory ();  
  10.             loggerFactory.AddProvider(new EFLoggerProvider());  
  11.             optionsBuilder.UseLoggerFactory(loggerFactory);  
  12.   
  13.             base.OnConfiguring(optionsBuilder);  
  14.         }  
  15.   
  16.         public DbSet<User> Users { getset; }  
  17.     }  

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

.NET Core实用技巧 如何将EF Core生成的SQL语句显示在控制台中

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

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

如何去除无关日志?

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

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

  1. public void Log<TState> (LogLevel logLevel,   
  2.         EventId eventId,   
  3.         TState state,   
  4.         Exception exception,   
  5.         Func<TState, Exception, string> formatter)  
  6.     {  
  7.   
  8.         if (categoryName == DbLoggerCategory.Database.Command.Name &&  
  9.             logLevel == LogLevel.Information) {  
  10.             var logContent = formatter (state, exception);  
  11.   
  12.             Console.WriteLine ();  
  13.             Console.ForegroundColor = ConsoleColor.Green;  
  14.             Console.WriteLine (logContent);  
  15.             Console.ResetColor ();  
  16.         }  
  17.     }  

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

.NET Core实用技巧 如何将EF Core生成的SQL语句显示在控制台中

如何显示敏感数据?

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

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

  1. class Program {  
  2.         static void Main (string[] args) {  
  3.   
  4.             var dbOptionBuilder = new DbContextOptionsBuilder<MyDbContext> ();  
  5.             dbOptionBuilder.UseMySql ("server=localhost;port=3306;database=EFCoreSampleDB;userid=root;pwd=a@12345");  
  6.   
  7.             using (var dbContext = new MyDbContext (dbOptionBuilder.Options)) {  
  8.                 dbContext.Users.Add(new User { UserId = Guid.NewGuid(), UserName = "Lamond Lu"});  
  9.                 dbContext.SaveChanges();  
  10.             }  
  11.         }  
  12.     }  

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

.NET Core实用技巧 如何将EF Core生成的SQL语句显示在控制台中

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

  1. protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder) {  
  2.        var loggerFactory = new LoggerFactory ();  
  3.        loggerFactory.AddProvider (new EFLoggerProvider ());  
  4.        optionsBuilder.EnableSensitiveDataLogging (true);  
  5.        optionsBuilder.UseLoggerFactory (loggerFactory);  
  6.   
  7.        base.OnConfiguring (optionsBuilder);  
  8.    }  

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

.NET Core实用技巧 如何将EF Core生成的SQL语句显示在控制台中

钰玺

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: