溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

發(fā)布時(shí)間:2020-07-18 13:49:38 來(lái)源:網(wǎng)絡(luò) 閱讀:519 作者:sshpp 欄目:網(wǎng)絡(luò)安全

顯式創(chuàng)建DbContext實(shí)例

通過(guò)帶OnConfiguring的構(gòu)造函數(shù)

這個(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中也是可以的如下:

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

public class EFCoreContext: DbContext
{    private readonly string _connectionString; 
    public EFCoreContext(string connectionString)
    {
        _connectionString = connectionString;
    } 
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)        => optionsBuilder.UseSqlServer(_connectionString);
}

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

使用不帶依賴(lài)注入的DbContextOptions 

在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,如下:

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

    public class EFCoreContext : DbContext
    {        public EFCoreContext(DbContextOptions options)
            : base(options)
        {
        }
    }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

    public class HomeController : Controller
    {        private static DbContextOptions _contextOptions;


        public IActionResult Index()
        {            _contextOptions = new DbContextOptionsBuilder()
            .UseSqlServer("")
            .Options;            using (var context = new EFCoreContext(_contextOptions))
            {

            }            return View();
        }
    }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

看到這里我們看到確確實(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)整。

使用依賴(lài)注入創(chuàng)建DbContext實(shí)例

我們只要在DI容器中注冊(cè)上下文類(lèi)型,然后它將被DI容器所解析,但是將上下文注冊(cè)到DI容器中我們就不用管了嗎,你還得注意到以下兩點(diǎn)。我們一般將其注入到DI容器中是這樣做的。

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

    public class EFCoreContext : DbContext
    {        public EFCoreContext(DbContextOptions options)
            : base(options)
        {
        }
    }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

            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)心。

帶有DbContextOptions的DI創(chuàng)建DbContext實(shí)例

我們?cè)贒I中注冊(cè)一個(gè)DbContextOptions實(shí)例還是有點(diǎn)用,它只會(huì)被創(chuàng)建一次并作為單例使用。比如我們可以初始化數(shù)據(jù)啊,如下

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

    public class EFCoreContext : DbContext
    {        public EFCoreContext(DbContextOptions options)
            : base(options)
        {
        }
    }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

        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();
        }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

現(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有如下屬性:

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

發(fā)現(xiàn)什么沒(méi)有,這個(gè)就是所有注入的服務(wù)的抽象屬性,我們將其轉(zhuǎn)換成EFCoreContext就可以在這個(gè)方法中初始化數(shù)據(jù),我們看看。

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

        private static EFCoreContext context;        public static void Initialize(IServiceProvider serviceProvider)
        {
            context = (EFCoreContext )serviceProvider.GetService(typeof(EFCoreContext ));            //do your something
        }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

使用泛型DbContextOptions創(chuàng)建DbContext實(shí)例

上述我們介紹的都是非泛型的DbContextOptions對(duì)象,如下:

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

     public class EFCoreContext : DbContext
     {        public EFCoreContext(DbContextOptions options) : base(options) { }        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.AddEntityConfigurationsFromAssembly(GetType().GetTypeInfo().Assembly);
        }
    }

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

但是其參數(shù)中的DbContextOptions還有一個(gè)泛型版本,那么泛型是用來(lái)干嘛的了,我們先看如下例子:

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

    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();

EntityFramework Core 1.1是如何創(chuàng)建DbContext實(shí)例的呢?

看到什么沒(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ì)被注入。

使用AddDbContext來(lái)創(chuàng)建DbContext實(shí)例

通過(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)有其他。


向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI