.NET Core技巧之SQL语句监控

390 阅读3分钟

本文已参与「新人创作礼」活动.一起开启掘金创作之路。

现有软件绝大多数都会和数据库进行交互,MySQL没有SQLServer的实时监视工具(SQL Server Profiler),在使用上只能通过配置慢日志或者其它第三方工具进行,而.NET Core则却使得这一困境得以改善,无论是在开发阶段、还是生产运行环境,均可以通过设置直接在项目的控制台显示相关SQL操作语句,以EF Core为例,我们来看一下如何通过.NET Core内置日志组件的实现方式SQL语句输出。

1、首先新建一个控制台程序,仅编写了一个最简单的EF查询:

namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var mySqlConnstr = "server=localhost;port=3306;database=testDB;userid=root;pwd=toor";
var dbOptionBuilder = new DbContextOptionsBuilder();
dbOptionBuilder.UseMySQL(mySqlConnstr);

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

此演示需提前创建了一个MySql数据库testDB和表users,并在项目中创建了一个对应的EF Core上下文。当前上下文中只有一个User实体,该实体用于储存用户信息,具有3个属性UserId、UserName和PassWord。


namespace ConsoleApp1
{
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions options) : base(options)
{

        }

        public DbSet Users { get; set; }

}

 public class User
{
[Key]
public int UserId { get; set;}
public string UserName { get; set;} 
public string PassWord{ get; set;}
}

2、将生成的SQL语句输出到控制台
.NET Core中提供了非常完善的日志接口,只需要实现2个接口,即可完成日志接口的集成,(一个是日志提供器接口ILoggerProvider, 一个是日志接口ILogger)。

EFLoggerProvider的代码非常的简单,就是直接返回一个我们后续创建的EFLogger对象:
public class EFLoggerProvider : ILoggerProvider {
public ILogger CreateLogger (string categoryName) => new EFLogger (categoryName);
public void Dispose () { }
}

EFLogger则可以通过设置控制输出显示, 这里我们主要使用了内置的formatter格式化了日志信息:

namespace ConsoleApp1
{
public class EFLogger : ILogger
{
private readonly string categoryName;

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

        public bool IsEnabled(LogLevel logLevel) => true;

        public void Log(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 state) => null;
}
}

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

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

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

            base.OnConfiguring(optionsBuilder);
}

4、启动项目,看一下效果,这里日志信息正确的显示出来了:

5、清除杂乱数据,仅显示SQL语句 
在前面的步骤中,可以看到控制台输出了查询语句,但是信息还是有些杂乱,无用信息较多,我们可以通过设置,清理一下无用日志。

在Log方法中,通过分类名称,只输出生成的SQL语句部分,即过滤和仅显示Microsoft.EntityFrameworkCore.Database.Command分类下的日志,上代码。

     public void Log (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语句。重新启动项目之后,效果如下。

6、如何显示完整的SQL语句的入参
先修改一下主程序,尝试向users表插入一条User信息。

   dbContext.Users.Add(new User { UserName = "TestUser" });
dbContext.SaveChanges();

重新运行程序,你会得到如下输出:

但是我们的入参,怎么不显示呢,由于EF Core默认关闭的敏感数据的显示配置,所以这里要通过DbContextOptionsBuilder对象的EnableSensitiveDataLogging方法修改敏感数据日志配置才能显示 :

        optionsBuilder.EnableSensitiveDataLogging (true);

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