查看原文
其他

多种方式创建 Entity Framework Core 上下文

喵叔 CSDN 2019-12-19

作者 | 喵叔
责编 | 刘静
出品 | CSDN(ID:CSDNnews)
我们在利用 Entity Framework Core 创建上下文实例的时候往往都是调用构造函数并重载 OnConfiguring 方法,这是 Entity Framework Core 默认的常用的创建上下文实例的方式。除了这种方式,微软也为我们准备了其他两种创建上下文实例的方式。算上常用的方式微软一共提供了三种创建上下文实例的方式,分别是:
  1. 直接调用上下文无参构造函数并重载 OnConfiguring 方法;

  2. 继承自上下文基类 DbContext 并传递 DbContextOptions 到上下文构造函数中;

  3. 使用依赖注入创建上下文实例。

上述三种方式总结起来就是两种创建上下文实例的方式,分别是 显示创建 和 通过依赖注入容器创建 。下面我分别来讲解这两种创建上下文实例的方式。

显示创建上下文实例

显示创建上下文实例是 Entity Framework Core 中常用的方式,当我们不需要通过依赖注入方式创建上下文实例的话就可以通过这种方式创建。
显示创建上下文实例最简单的方法是通过创建一个派生自 DbContext 的类,并且调用它的无参构造函数。代码如下:
public class EFContext : DbContext
{
    public EFContext(DbContextOptions options)
        :base(options)
    
{
    }
}

上述代码在运行时每次创建一个新的上下文实例都会调用 OnConfiguring 方法,这样我们可以通过利用 OnConfiguring 使用传递给上下文构造器或者其他实例的参数。这里需要注意的是每次调用上下文实例就必须使用 using 语句进行处理,也就是释放调用。

在 Entity Framework Core 中我们可以为每个上下文实例使用相同的 DbContextOptions 对象,这是因为 DbContext 构造函数可以接受 DbContextOptions 对象,它可以被显示调用可以通过它来隔离上下文。代码如下:
public class EFContext : DbContext
{
    public EFContext(DbContextOptions options)
        :base(options)
    
{
    }
}
class Program
{
    private static IServiceProvider serviceProvider;
    static void Main(string[] args)
    
{
        DbContextOptions context = new DbContextOptionsBuilder()
            .UseSqlServer("数据库连接字符串")
            .Options;
        var services = new ServiceCollection()
            .AddSingleton(context)
            .AddScoped<EFContext>();
        serviceProvider = services.BuildServiceProvider();
    }
}

上述代码中并没有进行重载 OnConfiguring 方法,但是在代码运行时 OnConfiguring 会被调用和重载,这时因为在进行注入上下文的时候会调用构造函数,还会对 OnConfiguring 进行调整。


依赖注入创建上下文实例

依赖注入上下文实例的方式有四种,分别是带无参构造函数的注入、带 DbContextOptions 实例的构造函数注入、使用泛型 DbContextOptions 注入和使用 AddDbContext 或 AddDbContextPool 注入。下面我分别来讲一讲。
1. 使用带无参构造函数的注入
DbContext 上下文派生类可以有一个无参数的构造函数并覆盖OnConfiguring方法。这样上下文类就没有任何依赖关系,这样除了上下文类型本身之外,其他任何内容都不需要在容器中注册。
2. 使用带 DbContextOptions 实例的构造函数注入
有时候需要在注入容器中注册 DbContextOptions 实例,将其注册为单例即可,这时我们只需要创建一次。下面我们以使用 DependencyInjection 为例来讲解一下,DependencyInjection 位于 Microsoft.Extensions.DependencyInjection 包中。代码如下:
public class EFContext : DbContext
{
    public EFContext(DbContextOptions options)
        :base(options)
    
{
    }
}
class Program
{
    private static IServiceProvider serviceProvider;
    static void Main(string[] args)
    
{
        DbContextOptions context = new DbContextOptionsBuilder()
            .UseSqlServer("数据库连接字符串")
            .Options;
        var services = new ServiceCollection()
            .AddSingleton(context)
            .AddScoped<EFContext>();
        serviceProvider = services.BuildServiceProvider();
    }
}

上述代码中通过 serviceProvider 将上下文注入容器中,DbContextOptions 实例也被注入到了构造函数中。

1. 使用泛型 DbContextOptions 注入
有时我们需要注册多个 DbContext 上下文类,这时我们就可以使用泛型 DbContextOptions,代码如下:
class Program
{
    private static IServiceProvider serviceProvider;
    static void Main(string[] args)
    
{
        DbContextOptions context1 = new DbContextOptionsBuilder()
            .UseSqlServer("数据库连接字符串1")
            .Options;
        DbContextOptions context2 = new DbContextOptionsBuilder()
            .UseSqlServer("数据库连接字符串2")
            .Options;
        var services = new ServiceCollection()
            .AddSingleton(context1)
            .AddScoped<EFContext1>()
            .AddSingleton(context2)
            .AddScoped<EFContext2>();
        serviceProvider = services.BuildServiceProvider();
    }
}

代码在运行时会按照顺序逐个注入,也是是说当代码解析到 EFContext1 时会注入 DbContextOptions<EFContext1>,解析到 EFContext2 时会注入 DbContextOptions<EFCoreDbContext2>

1. 使用 AddDbContext 或 AddDbContextPool 注入
使用 AddDbContext 或 AddDbContextPool 注入比较简单,只需要短短的几行代码即可:
static void Main(string[] args)
{
    var services = new ServiceCollection()
         .AddDbContext<EFContext>(p => p.UseSqlServer("数据库连接字符串"));
}

我们将 EFCoreDbContext 注册为 Scope,并将 DbContextOptions<EFCoreDbContext> 通过委托构建为单例。委托继续使用与 OnConfiguring 中相同的 DbContextOptionsBuilder。Scope 是默认的注册类型,如果不想注册为 Scope 可以通过向 AddDbContext 传参来更高,但是要注意的是因为DbContext非线程安全,因此不可传递 Singleton。


总结

通过上面的讲解你应该了解了创建上下文实例的方式,不过是普通方式和通过注入的方式在大型的项目中必须通过充分的研究再决定使用哪种方式,因为这两种方式在不同的环境下都有可能引起性能问题。另外还需要注意上下文实例在使用之后必须进行释放处理,另外上下文实例可以被注入为 Scoped 类型和 Transient 类型,但是唯独不能注入为 Singleton 类型,因为 DbContext上下文是非线程安全的。
作者简介:朱钢,笔名喵叔,CSDN博客专家,.NET高级开发工程师,7年一线开发经验,参与过电子政务系统和AI客服系统的开发,以及互联网招聘网站的架构设计,目前就职于北京恒创融慧科技发展有限公司,从事企业级安全监控系统的开发。
声明:本文系作者独立观点,不代表CSDN立场。
【END】

热 文 推 荐 

So easy!10 行代码写个“让你惊叹”的文章生成器 | 原力计划
31 岁的我为何会在创业成功后选择编程?
 微信推出“腾讯QQ”小程序;马化腾又要发红包;GitLab 12.5 稳定版发布| 极客头条
Facebook 与 Twitter 再曝漏洞!用户数据再次被共享?
Java 开发者最困惑的四件事
华为荣耀首款双模 5G 手机来了!

倪光南:中国 5G 有望成为世界第一

微信几亿人在线的点赞、取消点赞系统,用Redis如何实现?

量子算命,在线掷筊:一个IBM量子云计算机的应用实践,代码都有了

从黑客文化看区块链开源社区的自我组织与成功之道

 点击阅读原文,参加中国开发者现状调查!
你点的每个“在看”,我都认真当成了喜欢

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存