共用方式為


簡單記錄

提示

您可以從 GitHub 下載本文的範例

Entity Framework Core (EF Core) 簡單的記錄可用來在開發和偵錯應用程式時輕鬆取得記錄。 此形式的記錄需要最少的設定,而且不需要額外的 NuGet 套件。

提示

EF Core 也與 需要更多設定的 Microsoft.Extensions.Logging 整合,但通常更適合在生產應用程式中記錄。

組態

設定 DbCoNtext 執行個體時,可以使用 LogTo 從任何類型的應用程式存取 EF Core 記錄。 此設定通常是在 DbContext.OnConfiguring 的覆寫中完成。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(Console.WriteLine);

或者,在 建立實例以傳遞至建構函式時, LogTo 可以呼叫 作為 或 的 DbContextDbContextOptions 部分 AddDbContext

提示

使用 AddDbCoNtext 或 DbCoNtextOptions 實例傳遞至 DbCoNtext 建構函式時,仍會呼叫 OnConfiguring。 不論 DbCoNtext 的建構方式為何,這都適合套用內容組態。

指示記錄

記錄至主控台

LogToAction<T>需要接受字串的委派。 EF Core 會針對產生的每個記錄訊息,使用字串呼叫此委派。 接著,委派即可使用指定的訊息執行某些動作。

方法 Console.WriteLine 通常用於此委派,如上所示。 這會導致每個記錄訊息寫入主控台。

記錄至偵錯視窗

Debug.WriteLine 可用來將輸出傳送至 Visual Studio 或其他 IDE 中的 [偵錯] 視窗。 在此案例中必須使用 Lambda 語法 Debug 因為 類別是從發行組建編譯而來。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(message => Debug.WriteLine(message));

記錄至檔案

寫入檔案需要為檔案建立 StreamWriter 或類似的檔案。 WriteLine然後,方法可以和上述其他範例一樣使用。 請記得在處置內容時處置寫入器,以確保檔案完全關閉。 例如:

private readonly StreamWriter _logStream = new StreamWriter("mylog.txt", append: true);

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(_logStream.WriteLine);

public override void Dispose()
{
    base.Dispose();
    _logStream.Dispose();
}

public override async ValueTask DisposeAsync()
{
    await base.DisposeAsync();
    await _logStream.DisposeAsync();
}

提示

請考慮使用 Microsoft.Extensions.Logging 來記錄生產應用程式中的檔案。

取得詳細訊息

敏感性資料

根據預設,EF Core 不會在例外狀況訊息中包含任何資料的值。 這是因為這類資料可能是機密資料,而且如果未處理例外狀況,可能會顯示在生產環境中。

不過,瞭解資料值,尤其是索引鍵,在偵錯時可能會很有説明。 這可以在 EF Core 中藉由呼叫 EnableSensitiveDataLogging() 來啟用。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(Console.WriteLine)
        .EnableSensitiveDataLogging();

詳細的查詢例外狀況

基於效能考慮,EF Core 不會包裝每個呼叫,以從 try-catch 區塊中的資料庫提供者讀取值。 不過,這有時會導致難以診斷的例外狀況,特別是當模型不允許資料庫傳回 Null 時。

開啟 EnableDetailedErrors 會導致 EF 引進這些 try-catch 區塊,進而提供更詳細的錯誤。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(Console.WriteLine)
        .EnableDetailedErrors();

篩選

記錄層級

每個 EF Core 記錄訊息都會指派給列舉所 LogLevel 定義的層級。 根據預設,EF Core 簡單記錄包含層級 Debug 或更新層級的每個訊息。 LogTo 可以傳遞較高的最低層級來篩選掉某些訊息。 例如,傳遞 Information 會導致一組最低限度的記錄受限於資料庫存取和一些管家訊息。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);

特定訊息

每個記錄訊息都會指派 。 EventId 您可以從 類別或關聯式特定訊息的 RelationalEventId 類別存取 CoreEventId 這些識別碼。 資料庫提供者也可能在類似的類別中具有提供者特定的識別碼。 例如, SqlServerEventId 針對 SQL Server 提供者。

LogTo 可以設定為只記錄與一或多個事件識別碼相關聯的訊息。 例如,只記錄要初始化或處置之內容的訊息:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(Console.WriteLine, new[] { CoreEventId.ContextDisposed, CoreEventId.ContextInitialized });

訊息類別

每個記錄訊息都會指派給具名階層式記錄器類別。 這些類別包括:

類別 訊息
Microsoft.EntityFrameworkCore 所有 EF Core 訊息
Microsoft.EntityFrameworkCore.Database 所有資料庫互動
Microsoft.EntityFrameworkCore.Database。連線ion 資料庫連線的使用
Microsoft.EntityFrameworkCore.Database.Command 使用資料庫命令
Microsoft.EntityFrameworkCore.Database.Transaction 資料庫交易的使用
Microsoft.EntityFrameworkCore.Update 儲存實體,不包括資料庫互動
Microsoft.EntityFrameworkCore.Model 所有模型和中繼資料互動
Microsoft.EntityFrameworkCore.Model.Validation 模型驗證
Microsoft.EntityFrameworkCore.Query 查詢,不包括資料庫互動
Microsoft.EntityFrameworkCore.Infrastructure 一般事件,例如內容建立
Microsoft.EntityFrameworkCore.Scaffolding 資料庫反向工程
Microsoft.EntityFrameworkCore.Migrations 移轉
Microsoft.EntityFrameworkCore.ChangeTracking 變更追蹤互動

LogTo 可以設定為只記錄來自一或多個類別的訊息。 例如,若要只記錄資料庫互動:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(Console.WriteLine, new[] { DbLoggerCategory.Database.Name });

請注意,類別 DbLoggerCategory 會提供階層式 API 來尋找類別,並避免需要硬式程式碼字串。

由於類別是階層式的,因此使用類別的 Database 這個範例會包含子類別 Database.ConnectionDatabase.Command 、 和 Database.Transaction 的所有訊息。

自訂篩選

LogTo 允許將自訂篩選用於上述篩選選項都不夠的情況。 例如,若要記錄層級或更新版本 Information 的任何訊息,以及開啟和關閉連線的訊息:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .LogTo(
            Console.WriteLine,
            (eventId, logLevel) => logLevel >= LogLevel.Information
                                   || eventId == RelationalEventId.ConnectionOpened
                                   || eventId == RelationalEventId.ConnectionClosed);

提示

使用自訂篩選或使用這裡顯示的任何其他選項進行篩選比委派中的 LogTo 篩選更有效率。 這是因為如果篩選準則決定不應該記錄訊息,則甚至不會建立記錄訊息。

特定訊息的設定

EF Core ConfigureWarnings API 可讓應用程式變更遇到特定事件時會發生什麼事。 這可以用來:

  • 變更記錄檔層級,以記錄事件
  • 完全略過記錄事件
  • 事件發生時擲回例外狀況

變更事件的記錄層級

上述範例使用自訂篩選來記錄每個訊息, LogLevel.Information 以及針對 LogLevel.Debug 定義的兩個事件。 將兩 Debug 個事件的記錄層級變更為 Information ,即可達到相同的目的:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(
            b => b.Log(
                (RelationalEventId.ConnectionOpened, LogLevel.Information),
                (RelationalEventId.ConnectionClosed, LogLevel.Information)))
        .LogTo(Console.WriteLine, LogLevel.Information);

隱藏記錄事件

同樣地,個別事件可以從記錄中隱藏。 這特別適合忽略已檢閱和瞭解的警告。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Ignore(CoreEventId.DetachedLazyLoadingWarning))
        .LogTo(Console.WriteLine);

擲回事件

最後,EF Core 可以設定為針對指定的事件擲回。 這特別適用于將警告變更為錯誤。 (事實上,這是方法的原始 ConfigureWarnings 目的,因此是名稱。例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .ConfigureWarnings(b => b.Throw(RelationalEventId.MultipleCollectionIncludeWarning))
        .LogTo(Console.WriteLine);

郵件內容和格式設定

的預設 LogTo 內容會跨多行格式化。 第一行包含訊息中繼資料:

  • LogLevel做為四個字元前置詞的
  • 針對目前文化特性格式化的本機時間戳
  • EventId表單中的 ,可複製/貼上以取得成員或 CoreEventId 其中一個其他 EventId 類別的成員,加上原始識別碼值
  • 事件類別目錄,如上所述。

例如:

info: 10/6/2020 10:52:45.581 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE "Blogs" (
          "Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT,
          "Name" INTEGER NOT NULL
      );
dbug: 10/6/2020 10:52:45.582 RelationalEventId.TransactionCommitting[20210] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Committing transaction.
dbug: 10/6/2020 10:52:45.585 RelationalEventId.TransactionCommitted[20202] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Committed transaction.

您可以藉由傳遞 來自 DbContextLoggerOptions 的值來自訂此內容,如下列各節所示。

提示

請考慮使用 Microsoft.Extensions.Logging ,以進一步控制記錄格式設定。

使用 UTC 時間

根據預設,時間戳記是針對偵錯時的本機耗用量所設計。 請 DbContextLoggerOptions.DefaultWithUtcTime 改用與文化特性無關的 UTC 時間戳記,但保留其他所有專案。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(
        Console.WriteLine,
        LogLevel.Debug,
        DbContextLoggerOptions.DefaultWithUtcTime);

此範例會產生下列記錄格式:

info: 2020-10-06T17:55:39.0333701Z RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE "Blogs" (
          "Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT,
          "Name" INTEGER NOT NULL
      );
dbug: 2020-10-06T17:55:39.0333892Z RelationalEventId.TransactionCommitting[20210] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Committing transaction.
dbug: 2020-10-06T17:55:39.0351684Z RelationalEventId.TransactionCommitted[20202] (Microsoft.EntityFrameworkCore.Database.Transaction)
      Committed transaction.

單行記錄

有時候,每個記錄訊息只取得一行就很有用。 這可由 啟用 DbContextLoggerOptions.SingleLine 。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(
        Console.WriteLine,
        LogLevel.Debug,
        DbContextLoggerOptions.DefaultWithLocalTime | DbContextLoggerOptions.SingleLine);

此範例會產生下列記錄格式:

info: 10/6/2020 10:52:45.723 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) -> Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']CREATE TABLE "Blogs" (    "Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT,    "Name" INTEGER NOT NULL);
dbug: 10/6/2020 10:52:45.723 RelationalEventId.TransactionCommitting[20210] (Microsoft.EntityFrameworkCore.Database.Transaction) -> Committing transaction.
dbug: 10/6/2020 10:52:45.725 RelationalEventId.TransactionCommitted[20202] (Microsoft.EntityFrameworkCore.Database.Transaction) -> Committed transaction.

其他內容選項

中的 DbContextLoggerOptions 其他旗標可用來修剪記錄中包含的中繼資料數量。 這可以搭配單行記錄來使用。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(
        Console.WriteLine,
        LogLevel.Debug,
        DbContextLoggerOptions.UtcTime | DbContextLoggerOptions.SingleLine);

此範例會產生下列記錄格式:

2020-10-06T17:52:45.7320362Z -> Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']CREATE TABLE "Blogs" (    "Id" INTEGER NOT NULL CONSTRAINT "PK_Blogs" PRIMARY KEY AUTOINCREMENT,    "Name" INTEGER NOT NULL);
2020-10-06T17:52:45.7320531Z -> Committing transaction.
2020-10-06T17:52:45.7339441Z -> Committed transaction.

從 EF6 移動

EF Core 簡單記錄與 Database.Log EF6 不同,有兩個重要方式:

  • 記錄訊息不限於資料庫互動
  • 記錄必須在內容初始化時設定

針對第一個差異,上述篩選可用來限制記錄的訊息。

第二個差異是刻意變更,可藉由在不需要記錄訊息時產生記錄訊息來改善效能。 不過,您仍然可以藉由在您的 上 DbContext 建立 Log 屬性,然後只在設定屬性時,才能取得與 EF6 類似的行為。 例如:

public Action<string> Log { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(s => Log?.Invoke(s));