主頁 > .NET開發 > 002從零開始入門Entity Framework Core——DbContext生存期、配置和初始化

002從零開始入門Entity Framework Core——DbContext生存期、配置和初始化

2022-09-13 06:07:03 .NET開發

閱讀須知:本文為入門介紹、指引文章,所示代碼皆為最簡易(或僅為實作功能)的演示示例版本,不一定切實符合個人(企業)實際開發需求,

一、DbContext生存期

DbContext 的生存期從創建實體時開始,并在釋放實體時結束, DbContext 實體旨在用于單個作業單元,這意味著 DbContext 實體的生存期通常很短,

使用 Entity Framework Core (EF Core) 時的典型作業單元包括:

  • 創建 DbContext 實體
  • 根據背景關系跟蹤物體實體, 物體將在以下情況下被跟蹤
    • 正在從查詢回傳
    • 正在添加或附加到背景關系
  • 根據需要對所跟蹤的物體進行更改以實作業務規則
  • 呼叫 SaveChanges 或 SaveChangesAsync, EF Core 檢測所做的更改,并將這些更改寫入資料庫
  • 釋放 DbContext 實體
注意事項:
1、使用后釋放 DbContext 非常重要,這可確保釋放所有非托管資源,并注銷任何事件或其他掛鉤,以防止在實體保持參考時出現記憶體泄漏,
2、DbContext 不是執行緒安全的,不要在執行緒之間共享背景關系,請確保在繼續使用背景關系實體之前,等待所有異步呼叫,
3、EF Core 代碼引發的 InvalidOperationException 可以使背景關系進入不可恢復的狀態,此類例外指示程式錯誤,并且不旨在從其中恢復,

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

在許多 Web 應用程式中,每個 HTTP 請求都對應于單個作業單元,這使得背景關系生存期與請求的生存期相關,成為 Web 應用程式的一個良好默認值,

使用依賴關系注入配置 ASP.NET Core 應用程式,可以在 Startup.cs 檔案的 ConfigureServices 方法中,用 AddDbContext 擴展方法將 EF Core 添加到此處進行配置,

本文中我使用的是 MySQL 資料庫,例如:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    #region 配置MySQL資料庫
    var connectionString = "server=資料庫部署的服務器地址;user=資料庫登錄用戶名;password=資料庫登錄密碼;database=資料庫名;charset=utf8";
    var serverVersion = new MySqlServerVersion(new Version(5, 7, 22));
    services.AddDbContext<CustomAppDbContext>(
        dbContextOptions => dbContextOptions
            .UseMySql(connectionString, serverVersion)
    );
    #endregion
}

此示例將名為 CustomAppDbContext 的 DbContext 子類注冊為 ASP.NET Core 應用程式服務提供程式(也稱為依賴關系注入容器)中的作用域服務,背景關系配置為使用 MySQL 資料庫提供程式,并將從 ASP.NET Core 配置讀取連接字串,在 ConfigureServices 中的何處呼叫 AddDbContext 通常不重要,

F12轉到 DbContext 類的定義,發現其有參建構式定義形式為:

public DbContext([NotNullAttribute] DbContextOptions options);

CustomAppDbContext 類必須公開具有 DbContextOptions<CustomAppDbContext> 引數的公共建構式,這是將 AddDbContext 的背景關系配置傳遞到 DbContext 的方式,例如:

public class CustomAppDbContext : DbContext
{
    public CustomAppDbContext(DbContextOptions<CustomAppDbContext> options) : base(options)//呼叫父類的建構式
    {
    }
    
    public DbSet<Student> Student { get; set; }
}

其中 Student 類如下所示:

public partial class Student
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime? JoinTime { get; set; }
    public int Sex { get; set; }
}

然后,CustomAppDbContext 可以通過建構式注入在 ASP.NET Core 控制器或其他服務中使用,例如:

public class MyController : Controller
{
    private readonly CustomAppDbContext _context;
    
    public MyController(CustomAppDbContext context)//建構式
    {
        _context = context;
    }
    
    public JsonResult Index()
    {
        _context.Student.Add(new Student
        {
            Id = "10001",
            Name = "張三",
            JoinTime = DateTime.Now,
            Sex = 1
        });
        _context.SaveChanges();
        return new JsonResult("success");
    }
}

 最終結果是為每個請求創建一個 CustomAppDbContext 實體,并傳遞給控制器,以在請求結束后釋放前執行作業單元,

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

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

1、重寫 OnConfiguring 方法,

F12轉到 DbContext 類的定義,發現 OnConfiguring 方法的定義形式為:

protected internal virtual void OnConfiguring(DbContextOptionsBuilder optionsBuilder);

DbContext 子類的代碼示例如下所示:

public class NewCustomAppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql("server=資料庫部署的服務器地址;user=資料庫登錄用戶名;password=資料庫登錄密碼;database=資料庫名;charset=utf8", new MySqlServerVersion(new Version(5, 7, 22)));
    }
     
    public DbSet<Student> Student { get; set; }
}

此種方式構造的 DbContext 實體在控制器方法中呼叫如下所示:

public class MyNewController : Controller
{
    public string Index()
    {
        using  var db = new NewCustomAppDbContext();
        var list = db.Student.ToList();
        return JsonConvert.SerializeObject(list);
    }
}

2、通過 DbContext 建構式傳遞配置

通過此模式,我們還可以輕松地通過 DbContext 建構式傳遞配置(如連接字串),例如:

public class NewCustomAppDbContext : DbContext
{
    private readonly string _connectionString;
    
    public NewCustomAppDbContext(string connectionString)
    {
        _connectionString = connectionString;
    }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql(_connectionString, new MySqlServerVersion(new Version(5, 7, 22)));
    }
    
    public DbSet<Student> Student { get; set; }
}

此種方式構造的 DbContext 實體在控制器方法中呼叫如下所示:

public class MyNewController : Controller
{
    public string Index()
    {
        using  var db = new NewCustomAppDbContext("server=資料庫部署的服務器地址;user=資料庫登錄用戶名;password=資料庫登錄密碼;database=資料庫名;charset=utf8");
        var list = db.Student.ToList();
        return JsonConvert.SerializeObject(list);
    }
}

 3、使用 DbContextOptionsBuilder 創建 DbContextOptions 物件

可以使用 DbContextOptionsBuilder 創建 DbContextOptions 物件,然后將該物件傳遞到 DbContext 建構式,這使得為依賴關系注入配置的 DbContext 也能顯式構造,例如:

public class DICustomAppDbContext:DbContext
{
    public DICustomAppDbContext(DbContextOptions<DICustomAppDbContext> optionsBuilder):base(optionsBuilder)
    {
    }
    
    public DbSet<Student> Student { get; set; }
}

 此種構造方式,在 Controller 中可以創建 DbContextOptions,并可以顯式呼叫建構式,代碼如下所示:

public class MyDIController : Controller
{
    private readonly string _connectionString = "server=資料庫部署的服務器地址;user=資料庫登錄用戶名;password=資料庫登錄密碼;database=資料庫名;charset=utf8";
    private readonly MySqlServerVersion _serverVersion = new MySqlServerVersion(new Version(5, 7, 22));

    public string Index()
    {
        var contextOptions = new DbContextOptionsBuilder<DICustomAppDbContext>()
            .UseMySql(_connectionString, _serverVersion)
            .Options;
        using var context = new DICustomAppDbContext(contextOptions);
        var list = context.Student.ToList();
        return JsonConvert.SerializeObject(list);
    }
}

 四、使用 DbContext 工廠

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

在這些情況下,可以使用 AddDbContextFactory 來注冊工廠以創建 DbContext 實體,例如:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    #region 配置MySQL資料庫
    var connectionString = "server=資料庫部署的服務器地址;user=資料庫登錄用戶名;password=資料庫登錄密碼;database=資料庫名;charset=utf8";
    var serverVersion = new MySqlServerVersion(new Version(5, 7, 22));
    services.AddDbContextFactory<FactoryCustomAppDbContext>(
        dbContextOptions => dbContextOptions
            .UseMySql(connectionString, serverVersion)
    );
    #endregion
}

FactoryCustomAppDbContext 類必須公開具有 DbContextOptions<FactoryCustomAppDbContext> 引數的公共建構式,此模式與上面傳統 ASP.NET Core 部分中使用的模式相同,例如:

public class FactoryCustomAppDbContext : DbContext
{
    public FactoryCustomAppDbContext(DbContextOptions<FactoryCustomAppDbContext> options) : base(options)
    {
    }
    
    public DbSet<Student> Student { get; set; }
}

然后,可以通過建構式注入在其他服務中使用 DbContextFactory 工廠,最后,可以使用注入的工廠在服務代碼中構造 DbContext 實體,例如:

public class MyFactoryController : Controller
{
    private readonly IDbContextFactory<FactoryCustomAppDbContext> _contextFactory;
    
    public MyFactoryController(IDbContextFactory<FactoryCustomAppDbContext> contextFactory)
    {
        _contextFactory = contextFactory;
    }
    
    public string Index()
    {
        using (var context = _contextFactory.CreateDbContext())
        {
            var list = context.Student.ToList();
            return JsonConvert.SerializeObject(list);
        }
    }
}

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

五、DbContextOptions

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

  1. 在 AddDbContext 和相關方法中
  2. 在 OnConfiguring 中
  3. 使用 new 顯式構造

每種配置方式的示例在本文上述內容中都進行了講解和代碼展示,無論生成器來自何處,都可以應用相同的配置,此外,無論如何構造背景關系,都將始終呼叫 OnConfiguring,這意味著即使使用 AddDbContext,OnConfiguring 也可用于執行其他配置,

六、配置資料庫提供程式

每個 DbContext 實體都必須配置為使用一個且僅一個資料庫提供程式,(DbContext 子型別的不同實體可用于不同的資料庫提供程式,但一個實體只能使用一個,)一個資料庫提供程式要使用一個特定的 Use* 呼叫進行配置,

例如,若要使用 MySQL 資料庫提供程式:

public class MySQLAppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql("資料庫連接字串", new MySqlServerVersion(new Version(5, 7, 22)));
    }
}

例如,若要使用 SQL Server 資料庫提供程式:

public class SQLServerApplicationDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("資料庫連接字串");
    }
}

這些 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,其中包含類似于以下內容的訊息:

A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be thread safe.

翻譯成中文就是:

在上一個操作完成之前,在此背景關系上啟動了第二個操作,這通常是由不同執行緒使用相同的DbContext實體引起的,但不保證實體成員是執行緒安全的,

當并發訪問未被檢測到時,可能會導致未定義的行為、應用程式崩潰和資料損壞,

 七、異步操作缺陷

使用異步方法,EF Core 可以啟動以非阻擋式訪問資料庫的操作,但是,如果呼叫方不等待其中一個方法完成,而是繼續對 DbContext 執行其他操作,則 DbContext 的狀態可能會(并且很可能會)損壞,

應始終立即等待 EF Core 異步方法,

-------------------------------本篇文章到此結束-------------------------------------

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/506470.html

標籤:Entity Framework

上一篇:如何在C 中將指標地址作為命令列引數

下一篇:后增量的邏輯是什么?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more