您好,登錄后才能下訂單哦!
這個(gè)想必是我們最簡(jiǎn)單的方式了吧,通過(guò)調(diào)用繼承自DbContext的類(lèi)并且調(diào)用它的無(wú)參構(gòu)造函數(shù),同時(shí)我們需要謹(jǐn)記的時(shí)每當(dāng)實(shí)例化時(shí)我們都需要將其釋放也就是將其實(shí)例包裹在Using中。如下:
using (var context = new EFCoreContext()) { }
接著通過(guò)重載OnConfiguring來(lái)配置EF Core上下文實(shí)例,如下。
public class EFCoreContext: DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(@"Server=.;Database=EFTest;Trusted_Connection=True;"); }
【注意】:重載OnConfiguring和之前EF版本中的OnModelCreating創(chuàng)建模型不一樣,OnModelCreating創(chuàng)建模型上下文只實(shí)例化一次,但是OnConfiguring每實(shí)例化一個(gè)上下文時(shí)都會(huì)被調(diào)用一次,所以O(shè)nConfiguring能充分利用上下文中的構(gòu)造函數(shù)或者其他數(shù)據(jù)。
在EF 6.x中對(duì)于上下文有許多構(gòu)造函數(shù),例如連接字符串傳參,在EF Core 1.1中也是可以的如下:
public class EFCoreContext: DbContext { private readonly string _connectionString; public EFCoreContext(string connectionString) { _connectionString = connectionString; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(_connectionString); }
在DbContext的構(gòu)造函數(shù)中我們可以接受一個(gè)DbContextOptions對(duì)象,這個(gè)主要用在當(dāng)在DI容器中創(chuàng)建DbContext實(shí)例時(shí)會(huì)用到,當(dāng)然它也能被顯式調(diào)用,通過(guò)創(chuàng)建DbCOntextOptions對(duì)象來(lái)與上下文隔離,所以用它可以為每一個(gè)上下文的實(shí)例使用相同的options,如下:
public class EFCoreContext : DbContext { public EFCoreContext(DbContextOptions options) : base(options) { } }
public class HomeController : Controller { private static DbContextOptions _contextOptions; public IActionResult Index() { _contextOptions = new DbContextOptionsBuilder() .UseSqlServer("") .Options; using (var context = new EFCoreContext(_contextOptions)) { } return View(); } }
看到這里我們看到確確實(shí)實(shí)不再需要重載OnConfiguring,但是OnConfiguring將還是會(huì)被一直重載和調(diào)用,為什么會(huì)這樣尼,因?yàn)槲覀冊(cè)谂渲弥凶⑷肷舷挛乃鼤?huì)調(diào)用構(gòu)造函數(shù)并同時(shí)來(lái)對(duì)OnConfiguring進(jìn)行適當(dāng)?shù)恼{(diào)整。
我們只要在DI容器中注冊(cè)上下文類(lèi)型,然后它將被DI容器所解析,但是將上下文注冊(cè)到DI容器中我們就不用管了嗎,你還得注意到以下兩點(diǎn)。我們一般將其注入到DI容器中是這樣做的。
public class EFCoreContext : DbContext { public EFCoreContext(DbContextOptions options) : base(options) { } }
services.AddDbContext<EFCoreContext>(options => { options.UseSqlServer(sqlStr, d => d.MigrationsAssembly("StudyEFCore")); });
合情合理合法,但是為什么不能如下這樣用尼
services.AddSingleton<EFCoreContext>();
利用單例的形式注入難道就不行么,如果你這樣做了,你就等著程序崩潰吧,因?yàn)樯舷挛腄bContext不是線程安全的,也就是說(shuō)不能被注冊(cè)到單例來(lái)使用沒(méi)有額外的鎖。接著就是在將其注入到DI容器后,當(dāng)我們使用時(shí)還是用Using來(lái)包裹,你別以為注入到DI容器中就萬(wàn)事大吉它替你什么都做了,DI容器不會(huì)替你自動(dòng)處理,當(dāng)然了,如果你只是暫時(shí)在DI容器中使用的話,通常不會(huì)發(fā)生災(zāi)難。所以我們需要謹(jǐn)記如下兩點(diǎn)。
(1)將上下文注入到DI容器中后,當(dāng)使用DbContext依然還是用Using包括,因?yàn)镈I容器不會(huì)自動(dòng)將其釋放。
(2)DbContext是非線程安全的,即使是在DI容器中,也無(wú)非保證不出問(wèn)題,大部分情況下是不會(huì)有問(wèn)題的,不要擔(dān)心。
我們?cè)贒I中注冊(cè)一個(gè)DbContextOptions實(shí)例還是有點(diǎn)用,它只會(huì)被創(chuàng)建一次并作為單例使用。比如我們可以初始化數(shù)據(jù)啊,如下
public class EFCoreContext : DbContext { public EFCoreContext(DbContextOptions options) : base(options) { } }
private static IServiceProvider _serviceProvider; public IActionResult Index() { var contextOptions = new DbContextOptionsBuilder() .UseSqlServer("") .Options; var services = new ServiceCollection() .AddSingleton(contextOptions) .AddScoped<EFCoreContext>(); _serviceProvider = services.BuildServiceProvider(); return View(); }
現(xiàn)在EFCoreContext上下文將會(huì)被DI容器解析,通過(guò)將DbContextOptions實(shí)例將被注入到它的構(gòu)造函數(shù)中。這個(gè)_serviceProvider就是注入上下文的提供者,我們上述也說(shuō)了可以初始化數(shù)據(jù),如何初始化尼,來(lái)我們看看。在Startup.cs中有如下配置使用方法:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { .... }
這個(gè)app有如下屬性:
發(fā)現(xiàn)什么沒(méi)有,這個(gè)就是所有注入的服務(wù)的抽象屬性,我們將其轉(zhuǎn)換成EFCoreContext就可以在這個(gè)方法中初始化數(shù)據(jù),我們看看。
private static EFCoreContext context; public static void Initialize(IServiceProvider serviceProvider) { context = (EFCoreContext )serviceProvider.GetService(typeof(EFCoreContext )); //do your something }
上述我們介紹的都是非泛型的DbContextOptions對(duì)象,如下:
public class EFCoreContext : DbContext { public EFCoreContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.AddEntityConfigurationsFromAssembly(GetType().GetTypeInfo().Assembly); } }
但是其參數(shù)中的DbContextOptions還有一個(gè)泛型版本,那么泛型是用來(lái)干嘛的了,我們先看如下例子:
public class EFCoreContext1 : DbContext { public EFCoreContext1text1(DbContextOptions<EFCoreContext1> options) : base(options) { } } public class EFCoreContext2 : DbContext { public EFCoreContext2(DbContextOptions<EFCoreContext2> options) : base(options) { } } var contextOptions1 = new DbContextOptionsBuilder<EFCoreContext1>() .UseSqlServer(connectionString1) .Options; var contextOptions2 = new DbContextOptionsBuilder<EFCoreContext2>() .UseSqlServer(connectionString2) .Options; var services = new ServiceCollection() .AddSingleton(contextOptions1) .AddScoped<EFCoreContext1>() .AddSingleton(contextOptions2) .AddScoped<EFCoreContext2>(); _serviceProvider = services.BuildServiceProvider();
看到什么沒(méi)有,如果有多個(gè)上下文類(lèi)型在DI容器中注冊(cè)時(shí)我們可以允許每個(gè)上下文的類(lèi)型都依賴(lài)于自己的Options。當(dāng)解析EFCoreContext1時(shí)將會(huì)導(dǎo)致DbContextOptions<EFCoreContext1>會(huì)被注入,同理當(dāng)解析EFCoreContext2時(shí)將導(dǎo)致DbContextOptions<EFCoreContext2>會(huì)被注入。
通過(guò)AddDbContext語(yǔ)法糖來(lái)注冊(cè)DbContext和DbContextOptions實(shí)例。如下:
var services = new ServiceCollection() .AddDbContext<EFCoreContext>( b => b.UseSqlServer(connectionString));
默認(rèn)情況下將EFCoreContext作為scope進(jìn)行注冊(cè),將DbContextOptions作為單例進(jìn)行注冊(cè),你可更改將EFCoreContext作為單例注冊(cè),上述我們已經(jīng)討論過(guò)這個(gè)問(wèn)題了啊。好了到了這里想必我們知道創(chuàng)建EF Core上下文實(shí)例的幾種方式了吧,我們概括為以下三點(diǎn)。
(1)直接調(diào)用上下文構(gòu)造函數(shù)并重載OnConfiguring創(chuàng)建上下文實(shí)例。
(2)傳遞DbContextOptions到構(gòu)造函數(shù)中創(chuàng)建上下文實(shí)例。
(3)通過(guò)DI容器來(lái)創(chuàng)建上下文實(shí)例。
使用DbContextOptionsBuilder來(lái)配置一個(gè)DbContext并最終構(gòu)造一個(gè)DbContextOptions對(duì)象,這也能夠通過(guò)重載OnConfiguring方法或者通過(guò)構(gòu)造options來(lái)傳遞到DbContext的構(gòu)造函數(shù)中去,無(wú)論是通過(guò)無(wú)參構(gòu)造函數(shù)還是通過(guò)DbContextOptions傳遞到上下文的構(gòu)造函數(shù)中去,抑或是通過(guò)將DbContext注入到DI容器中去都是一樣的,都沒(méi)有什么本質(zhì)區(qū)別,只不過(guò)通過(guò)DI簡(jiǎn)便一點(diǎn)而且逼格比較高而已,沒(méi)有其他。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。