您好,登錄后才能下訂單哦!
這個想必是我們最簡單的方式了吧,通過調用繼承自DbContext的類并且調用它的無參構造函數,同時我們需要謹記的時每當實例化時我們都需要將其釋放也就是將其實例包裹在Using中。如下:
using (var context = new EFCoreContext()) { }
接著通過重載OnConfiguring來配置EF Core上下文實例,如下。
public class EFCoreContext: DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(@"Server=.;Database=EFTest;Trusted_Connection=True;"); }
【注意】:重載OnConfiguring和之前EF版本中的OnModelCreating創建模型不一樣,OnModelCreating創建模型上下文只實例化一次,但是OnConfiguring每實例化一個上下文時都會被調用一次,所以OnConfiguring能充分利用上下文中的構造函數或者其他數據。
在EF 6.x中對于上下文有許多構造函數,例如連接字符串傳參,在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的構造函數中我們可以接受一個DbContextOptions對象,這個主要用在當在DI容器中創建DbContext實例時會用到,當然它也能被顯式調用,通過創建DbCOntextOptions對象來與上下文隔離,所以用它可以為每一個上下文的實例使用相同的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(); } }
看到這里我們看到確確實實不再需要重載OnConfiguring,但是OnConfiguring將還是會被一直重載和調用,為什么會這樣尼,因為我們在配置中注入上下文它會調用構造函數并同時來對OnConfiguring進行適當的調整。
我們只要在DI容器中注冊上下文類型,然后它將被DI容器所解析,但是將上下文注冊到DI容器中我們就不用管了嗎,你還得注意到以下兩點。我們一般將其注入到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>();
利用單例的形式注入難道就不行么,如果你這樣做了,你就等著程序崩潰吧,因為上下文DbContext不是線程安全的,也就是說不能被注冊到單例來使用沒有額外的鎖。接著就是在將其注入到DI容器后,當我們使用時還是用Using來包裹,你別以為注入到DI容器中就萬事大吉它替你什么都做了,DI容器不會替你自動處理,當然了,如果你只是暫時在DI容器中使用的話,通常不會發生災難。所以我們需要謹記如下兩點。
(1)將上下文注入到DI容器中后,當使用DbContext依然還是用Using包括,因為DI容器不會自動將其釋放。
(2)DbContext是非線程安全的,即使是在DI容器中,也無非保證不出問題,大部分情況下是不會有問題的,不要擔心。
我們在DI中注冊一個DbContextOptions實例還是有點用,它只會被創建一次并作為單例使用。比如我們可以初始化數據啊,如下
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(); }
現在EFCoreContext上下文將會被DI容器解析,通過將DbContextOptions實例將被注入到它的構造函數中。這個_serviceProvider就是注入上下文的提供者,我們上述也說了可以初始化數據,如何初始化尼,來我們看看。在Startup.cs中有如下配置使用方法:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { .... }
這個app有如下屬性:
發現什么沒有,這個就是所有注入的服務的抽象屬性,我們將其轉換成EFCoreContext就可以在這個方法中初始化數據,我們看看。
private static EFCoreContext context; public static void Initialize(IServiceProvider serviceProvider) { context = (EFCoreContext )serviceProvider.GetService(typeof(EFCoreContext )); //do your something }
上述我們介紹的都是非泛型的DbContextOptions對象,如下:
public class EFCoreContext : DbContext { public EFCoreContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.AddEntityConfigurationsFromAssembly(GetType().GetTypeInfo().Assembly); } }
但是其參數中的DbContextOptions還有一個泛型版本,那么泛型是用來干嘛的了,我們先看如下例子:
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();
看到什么沒有,如果有多個上下文類型在DI容器中注冊時我們可以允許每個上下文的類型都依賴于自己的Options。當解析EFCoreContext1時將會導致DbContextOptions<EFCoreContext1>會被注入,同理當解析EFCoreContext2時將導致DbContextOptions<EFCoreContext2>會被注入。
通過AddDbContext語法糖來注冊DbContext和DbContextOptions實例。如下:
var services = new ServiceCollection() .AddDbContext<EFCoreContext>( b => b.UseSqlServer(connectionString));
默認情況下將EFCoreContext作為scope進行注冊,將DbContextOptions作為單例進行注冊,你可更改將EFCoreContext作為單例注冊,上述我們已經討論過這個問題了啊。好了到了這里想必我們知道創建EF Core上下文實例的幾種方式了吧,我們概括為以下三點。
(1)直接調用上下文構造函數并重載OnConfiguring創建上下文實例。
(2)傳遞DbContextOptions到構造函數中創建上下文實例。
(3)通過DI容器來創建上下文實例。
使用DbContextOptionsBuilder來配置一個DbContext并最終構造一個DbContextOptions對象,這也能夠通過重載OnConfiguring方法或者通過構造options來傳遞到DbContext的構造函數中去,無論是通過無參構造函數還是通過DbContextOptions傳遞到上下文的構造函數中去,抑或是通過將DbContext注入到DI容器中去都是一樣的,都沒有什么本質區別,只不過通過DI簡便一點而且逼格比較高而已,沒有其他。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。