.NET Core實用技巧(一)如何將EF Core生成的SQL語句顯示在控制檯中
阿新 • • 發佈:2020-08-24
![](https://img2020.cnblogs.com/blog/65831/202008/65831-20200823223113168-1806256062.jpg)
# 目錄
- .NET Core實用技巧(一)如何將EF Core生成的SQL語句顯示在控制檯中
# 前言
筆者最近在開發和維護一個.NET Core專案,其中使用幾個非常有意思的.NET Core相關的擴充套件,在此總結整理一下。
# EF Core效能調優
如果你的專案中使用了EF Core, 且正在處於效能調優階段,那麼瞭解EF Core生成的SQL語句是非常關鍵的。那麼除了使用第三方工具,如何檢視EF Core生成的SQL語句呢?這裡筆者將給出一個基於.NET Core內建日誌元件的實現方式。
# 建立一個例項專案
我們首先建一個控制檯程式,在主程式中我們編寫了一個最簡單的EF查詢。
```c#
class Program {
static void Main (string[] args) {
var dbOptionBuilder = new DbContextOptionsBuilder();
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`。
```c#
public class MyDbContext : DbContext {
public MyDbContext (DbContextOptions options) : base (options) {
}
public DbSet Users { get; set; }
}
```
```c#
public class User
{
[Key]
public Guid UserId { get; set;}
public string UserName { get; set;}
}
```
# 如何生成的SQL語句輸出到控制檯?
.NET Core中提供了非常完善的日誌介面。這裡為了和.NET Core的日誌介面整合,我們需要實現2個介面,一個是日誌提供器介面`ILoggerProvider`, 一個是日誌介面`ILogger`
`EFLoggerProvider.cs`
```c#
public class EFLoggerProvider : ILoggerProvider {
public ILogger CreateLogger (string categoryName) => new EFLogger (categoryName);
public void Dispose () { }
}
```
`EFLoggerProvider`的程式碼非常的簡單,就是直接返回一個我們後續建立的`EFLogger`物件。
`EFLogger.cs`
```c#
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 formatter) {
var logContent = formatter (state, exception);
Console.WriteLine ();
Console.WriteLine (logContent);
}
}
public IDisposable BeginScope (TState state) => null;
}
```
這裡我們主要使用了內建的`formatter`格式化了日誌資訊。
最後我們還需要將自定義的日誌處理類和EF Core整合起來。這裡我們需要複寫上下文類的`OnConfiguring`方法。在其中通過`UseLoggerFactory`方法,將我們自定義的日誌處理類和EF Core的日誌系統關聯起來。
```c#
public class MyDbContext : DbContext {
public MyDbContext (DbContextOptions 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 Users { get; set; }
}
```
下面我們啟動專案,看一下效果。這裡日誌資訊正確的顯示出來了。
![](https://img2020.cnblogs.com/blog/65831/202008/65831-20200823223122384-742027900.jpg)
> PS: 如果專案中使用了通用主機或者ASP.NET Core, 你也可以在服務配置部分,通過`DbContextOptions`引數配置。
>
> ```c#
> services.AddDbContext(options =>
> options.UseSqlServer(Configuration.GetConnectionString("MyDb"))
> .UseLoggerFactory(new LoggerFactory()));
> ```
# 如何去除無關日誌?
在前面的步驟中,我們成功的輸出了查詢語句,但是有一個問題是我們只想檢視輸出的SQL語句,其他的資訊我們都不想要,那麼能不能去除掉這些無關日誌呢?答案是肯定的。
我們可以在`Log`方法中,通過分類名稱,只輸出`Microsoft.EntityFrameworkCore.Database.Command`分類下的日誌,該日誌即生成的SQL語句部分。
```c#
public void Log (LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func 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語句。重新啟動專案之後,效果如下。
![](https://img2020.cnblogs.com/blog/65831/202008/65831-20200823223128682-1537688637.jpg)
# 如何顯示敏感資料?
這裡看似我們已經完成了EF Core的語句輸出,但是在實際使用中,你還會遇到另外一個問題。
下面我們修改一下我們的主程式,我們嘗試插入一條`User`資訊。
```c#
class Program {
static void Main (string[] args) {
var dbOptionBuilder = new DbContextOptionsBuilder ();
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();
}
}
}
```
重新執行程式,你會得到一下結果。
![](https://img2020.cnblogs.com/blog/65831/202008/65831-20200823223134741-1766373194.jpg)
這裡你可能會問為什麼不顯示@p0, @p1引數的值。這裡是原因是為了保護敏感資料,EF Core預設關閉的敏感資料的顯示配置,如果你想要檢視敏感資料,你需要通過`DbContextOptionsBuilder`物件的`EnableSensitiveDataLogging`方法修改敏感資料日誌配置。
```c#
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引數的值了。
![](https://img2020.cnblogs.com/blog/65831/202008/65831-20200823223140458-45506706.jpg)