EntityFramework Core 1.1是如何创建DbContext实例的呢?

前言

上一篇我们简单讲述了在EF Core1.1中如何进行迁移,本文我们来讲讲EF Core1.1中那些不为人知的事,细抠细节,从我做起。

显式创建DbContext实例

通过带OnConfiguring的构造函数

这个想必是我们最简单的方式了吧,通过调用继承自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);
}

使用不带依赖注入的DbContextOptions 

在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进行适当的调整。

使用依赖注入创建DbContext实例

我们只要在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容器中,也无非保证不出问题,大部分情况下是不会有问题的,不要担心。

带有DbContextOptions的DI创建DbContext实例

我们在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创建DbContext实例

上述我们介绍的都是非泛型的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实例

通过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简便一点而且逼格比较高而已,没有其他。

总结

好了,本节我们对于EF Core 1.1中创建上下文的几种方式都已叙述完毕,你是否已经Understand呢,晚安,世界,又熬夜了。

时间: 2024-09-20 13:46:45

EntityFramework Core 1.1是如何创建DbContext实例的呢?的相关文章

EntityFramework 7 更名为EntityFramework Core(预发布状态)

前言 最近很少去学习和探索新的东西,尤其是之前一直比较关注的EF领域,本身不太懒,但是苦于环境比较影响自身的心情,所以迟迟没有下笔,但是不去学习感觉在精神层面缺少点什么,同时也有园友说EF又更新了,要我再写一篇,最终经过思想斗争后,还是花了一点时间去继续探索.本篇比较理论的去分享最近EF进展,后面有时间会继续关注EF团队在EF上的动向,并给出相对应的实例. EF Core 1.0.0 (1)EntityFramework是微软在.NET中推荐使用的数据访问技术,而EntityFramework

EntityFramework Core 1.1有哪些新特性呢?我们需要知道

前言 在项目中用到EntityFramework Core都是现学现用,及时发现问题及时测试,私下利用休闲时间也会去学习其他未曾遇到过或者用过的特性,本节我们来讲讲在EntityFramework Core 1.1中出现了哪些新特性供我们使用. EntityFramework Core 1.1新特性探讨 DbSet.Find 在EF 6.x中也有此方法的实现,在EF Core 1.1中也同样对此方法进行了实现,为什么要拿出来讲呢,当然也有其道理,我们一起来看看.在仓储中我们实现Find这个方法,

神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观

前言 哦,不搞SQL了么,当然会继续,周末会继续更新,估计写完还得几十篇,但是我会坚持把SQL更新完毕,绝不会烂尾,后续很长一段时间没更新的话,不要想我,那说明我是学习新的技能去了,那就是学习英语,本来没有打算再探究目前.NET中跨平台的东西,毕竟才出来没多久,还是有很多坑,希望有人踩过再来学习会好很多,可惜项目中都是用的最新的东西,我不得不去探索,于是有关EntityFramework Core的坑就这么出来了,来,我们一起看看. EntityFramework Core 1.1迁移 我们首先

EntityFramework Core饥饿加载忽略导航属性问题

前言 .NET Core项目利用EntityFramework Core作为数据访问层一直在进行中,一直没有过多的去关注背后生成的SQL语句,然后老大捞出日志文件一看,恩,有问题了,所以本文产生了,也是有点疑惑,若有知情者,还望告知. EntityFramework Core忽略导航属性  在前面我们已经探讨过利用Serilog日志框架来输出日志,所以对于本节查询日志的输出依然借助Seilog.我们在Startup.cs类中Starup方法中是创建日志实例. Log.Logger = new L

Do You Kown Asp.Net Core - 根据实体类自动创建Razor Page CURD页面模板

Scaffolding Template Intro 我们知道在Asp.Net MVC中,如果你使用的EF的DBContext的话,你可以在vs中通过右键解决方案-添加控制器-添加包含视图的控制器,然后vs会根据你选择的Model自动生成相应的CURD的控制器和View,非常便利,这种就叫做 ASP.NET Scaffolding Template,之前雪燕大大有过一篇介绍,有兴趣可以看看[传送门] 大家知道近期Asp.Net Core2.0发布了,微软也推出了Razor Page来作为默认的A

EntityFramework Core并发深挖详解,一纸长文,你准备好看完了吗?

前言 之前有关EF并发探讨过几次,但是呢,博主感觉还是有问题,为什么会觉得有问题,其实就是理解不够透彻罢了,于是在项目中都是用的存储过程或者SQL语句来实现,利用放假时间好好补补EF Core并发的问题,本文比较长,请耐心点看. EntityFramework Core并发初级版初探 关于并发无非就两种:乐观并发和悲观并发,悲观并发简言之则是当客户端对数据库中同一值进行修改时会造成阻塞,而乐观并发则任何客户端都可以对可以对数据进行查询或者读取,在EF Core中不支持悲观并发,结果则产生并发冲突

EntityFramework Core并发导致显式插入主键问题

前言 之前讨论过EntityFramework Core中并发问题,按照官网所给并发冲突解决方案以为没有什么问题,但是在做单元测试时发现too young,too simple,下面我们一起来看看. .NET Core 1.1单元测试问题 我们循序渐进,首先从单元测试开始说起,可能其中就有你在.NET Core上进行单元测试会遇到的问题,别着急,不妨一看.我们需要创建.NET Core类库,,如下: 接下来对project.json进行如下修改. { "version": "

EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6.x中不同,相同的则不再叙述. EntityFramework Core 1.1方法理论详解 当我们利用EF Core查询数据库时如果我们不显式关闭变更追踪的话,此时实体是被追踪的,关于变更追踪我们下节再叙.就像我们之前在EF 6.x中讨论的那样,不建议手动关闭变更追踪,对于有些特殊情况下,关闭变更追

EntityFramework Core Raw Query再叙注意事项后续

前言 话说通过EntityFramwork Core进行原始查询又出问题,且听我娓娓道来. EntityFramework Core Raw Query后续 当我们进行复杂查询时我们会通过原始查询来进行,我们定义如下ViewModel public class BlogViewModel { public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } public str