Entity Framework Core - DbContext配置和初始化


DbContext生存期

  DbContext的生存期從創建實例開始,並在釋放實例時結束。DbContext實例旨在用於單個工作單元。這意味着DbContext實例的生存期通常很短。

  工作單元維護受業務交易影響的對象的列表,並協調更改的注銷和並發問題的解決。

在將數據移入和移出數據庫時,重要的是要跟蹤所做的更改。否則,該數據將不會被寫回到數據庫中。同樣,您必須插入創建的新對象並刪除所有刪除的對象。

您可以隨着對象模型的每次更改來更改數據庫,但是這可能導致許多非常小的數據庫調用,這最終會非常緩慢此外,它要求您為整個交互打開一個事務,如果您的業務事務跨越多個請求,則這是不切實際的。如果您需要跟蹤已讀取的對象,從而避免不一致的讀取,則情況甚至更糟。

工作單元會跟蹤您在業務交易過程中可能影響數據庫的所有操作。完成后,它會計算出由於工作而需要更改數據庫的所有工作。英文原文請參考:EAA的P

  EF Core的典型工作單元包括(重點理解這段,有助於我們對EF Core工作原理的理解):

  • 創建DbContext實例
  • 根據上下文跟蹤實體實例。實體將在以下情況下被追蹤
    • 正在從查詢返回
    • 正在添加或附加到上下文
  • 根據需要對所跟蹤的實體進行更改以實現業務規則
  • 調用SaveChanges或SaveChangesAsync。EF Core檢測所做的更改,並將這些更改寫入到數據庫
  • 釋放DbContext

  重要知識點:

  • 使用后釋放DbContext非常重要。這可確保釋放所有非托管資源,並注銷任何事件或其他掛鈎,以防止在實例保持引用時出現內存泄漏。
  • DbContext不是線程安全的。不要在線程間共享上下文。請確保在繼續使用上下文實例之前,等待所有異步調用。
  • EF Core引發的InvalidOperationException可以使上下文進入不可恢復狀態。

ASP.NET Core 依賴關系注入中的 DbContext

  在許多 Web 應用程序中,每個 HTTP 請求都對應於單個工作單元。 這使得上下文生存期與請求的生存期相關。

  使用依賴關系注入配置 ASP.NET Core 應用程序。 可以使用 Startup.cs 的 ConfigurureServices 方法中的 AddDbContext 將 EF Core 添加到此配置。 例如:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    services.AddDbContext<ApplicationDbContext>(
        options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}

  此示例將名為 ApplicationDbContext 的 DbContext 子類注冊為 ASP.NET Core 應用程序服務提供程序(也稱為 依賴關系注入容器)中的作用域服務。 

  options => options.UseSqlServer上下文配置為使用 SQL Server 數據庫提供程序,
  "name=ConnectionStrings:DefaultConnection"表示將從 ASP.NET Core 配置讀取連接字符串。 在 ConfigureServices 中的何處調用 AddDbContext 通常不重要。

  ApplicationDbContext (數據庫上下文)類必須公開具有 DbContextOptions<ApplicationDbContext> 參數的公共構造函數。 這是將 AddDbContext 的上下文配置傳遞到 DbContext 的方式。 例如:

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

  然后,ApplicationDbContext 可以通過構造函數注入在 ASP.NET Core 控制器或其他服務中使用。 例如:

1 public class MyController
2 {
3     private readonly ApplicationDbContext _context;
4 
5     public MyController(ApplicationDbContext context)
6     {
7         _context = context;
8     }
9 }

  最終結果是為每個請求創建一個 ApplicationDbContext 實例,並傳遞給控制器,以在請求結束后釋放前執行工作單元。

使用“new”的簡單的 DbContext 初始化

  可以按照常規的 .NET 方式構造 DbContext 實例,例如,使用 C# 中的 new。 可以通過重寫 OnConfiguring 方法或通過將選項傳遞給構造函數來執行配置。 例如:

1 public class ApplicationDbContext : DbContext
2 {
3     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
4     {
5         optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
6     }
7 }

  通過此模式,還可以輕松地通過 DbContext 構造函數傳遞配置(如連接字符串)。 例如:

 1 public class ApplicationDbContext : DbContext
 2 {
 3     private readonly string _connectionString;
 4 
 5     public ApplicationDbContext(string connectionString)
 6     {
 7         _connectionString = connectionString;
 8     }
 9 
10     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
11     {
12         optionsBuilder.UseSqlServer(_connectionString);
13     }
14 }

  或者,可以使用 DbContextOptionsBuilder 創建 DbContextOptions 對象,然后將該對象傳遞到 DbContext 構造函數。 這使得為依賴關系注入配置的 DbContext 也能顯式構造。 例如,使用上述為 ASP.NET Core 的 Web 應用定義的 ApplicationDbContext 時:

1 public class ApplicationDbContext : DbContext
2 {
3     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
4         : base(options)
5     {
6     }
7 }

  可以創建 DbContextOptions,並可以顯式調用構造函數:

var contextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
    .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test")
    .Options;

using var context = new ApplicationDbContext(contextOptions);

使用 DbContext 工廠(例如對於 Blazor)

  某些應用程序類型(例如 ASP.NET Core Blazor)使用依賴關系注入,但不創建與所需的 DbContext 生存期一致的服務作用域。 即使存在這樣的對齊方式,應用程序也可能需要在此作用域內執行多個工作單元。 例如,單個 HTTP 請求中的多個工作單元。在這些情況下,可以使用 AddDbContextFactory 來注冊工廠以創建 DbContext 實例。 例如:

1 public void ConfigureServices(IServiceCollection services)
2 {
3     services.AddDbContextFactory<ApplicationDbContext>(options =>
4         options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"));
5 }

  ApplicationDbContext 類必須公開具有 DbContextOptions<ApplicationDbContext> 參數的公共構造函數。 此模式與上面傳統 ASP.NET Core 部分中使用的模式相同。

1 public class ApplicationDbContext : DbContext
2 {
3     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
4         : base(options)
5     {
6     }
7 }

  然后,可以通過構造函數注入在其他服務中使用 DbContextFactory 工廠。 例如:

1 private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
2 
3 public MyController(IDbContextFactory<ApplicationDbContext> contextFactory)
4 {
5     _contextFactory = contextFactory;
6 }

  然后,可以使用注入的工廠在服務代碼中構造 DbContext 實例。 例如:

1 public void DoSomething()
2 {
3     using (var context = _contextFactory.CreateDbContext())
4     {
5         // ...
6     }
7 }

  請注意,以這種方式創建的 DbContext 實例並非由應用程序的服務提供程序進行管理,因此必須由應用程序釋放。

DbContextOptions

  所有 DbContext 配置的起始點都是 DbContextOptionsBuilder。 可以通過三種方式獲取此生成器:

  • 在 AddDbContext 和相關方法中
  • 在 OnConfiguring 中
  • 使用 new 顯式構造

  上述各節顯示了其中每個示例。 無論生成器來自何處,都可以應用相同的配置。 此外,無論如何構造上下文,都將始終調用 OnConfiguring。 這意味着即使使用 AddDbContextOnConfiguring 也可用於執行其他配置。

 

配置數據庫提供程序

  每個 DbContext 實例都必須配置為使用一個且僅一個數據庫提供程序。 DbContext 子類型的不同實例可用於不同的數據庫提供程序,但單個實例只能使用一個。)使用特定的 Use*" 調用配置數據庫提供程序。 例如,若要使用 SQL Server 數據庫提供程序:

1 public class ApplicationDbContext : DbContext
2 {
3     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
4     {
5         optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
6     }
7 }

  這些 Use*" 方法是由數據庫提供程序實現的擴展方法。 這意味着必須先安裝數據庫提供程序 NuGet 包,然后才能使用擴展方法。

  EF Core 數據庫提供程序廣泛使用擴展方法。 如果編譯器指示找不到方法,請確保已安裝提供程序的 NuGet 包,並且你在代碼中已有 using Microsoft.EntityFrameworkCore;

  下表包含常見數據庫提供程序的示例:

數據庫系統

配置示例

NuGet 程序包
SQL Server 或 Azure SQL .UseSqlServer(connectionString) Microsoft.EntityFrameworkCore.SqlServer
Azure Cosmos DB .UseCosmos(connectionString, databaseName) Microsoft.EntityFrameworkCore.Cosmos
SQLite .UseSqlite(connectionString) Microsoft.EntityFrameworkCore.Sqlite
EF Core 內存中數據庫 .UseInMemoryDatabase(databaseName) Microsoft.EntityFrameworkCore.InMemory
PostgreSQL* .UseNpgsql(connectionString) Npgsql.EntityFrameworkCore.PostgreSQL
MySQL/MariaDB* .UseMySql((connectionString) Pomelo.EntityFrameworkCore.MySql
Oracle* .UseOracle(connectionString) Oracle.EntityFrameworkCore

避免 DbContext 線程處理問題

  Entity Framework Core 不支持在同一 DbContext 實例上運行多個並行操作。 這包括異步查詢的並行執行以及從多個線程進行的任何顯式並發使用。 因此,始終立即 await 異步調用,或對並行執行的操作使用單獨的 DbContext 實例。

  當 EF Core 檢測到嘗試同時使用 DbContext 實例的情況時,你將看到 InvalidOperationException

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM