002从零开始入门Entity Framework Core——DbContext生存期、配置和初始化

阅读须知:本文为入门介绍、指引文章,所示代码皆为最简易(或仅为实现功能)的演示示例版本,不一定切实符合个人(企业)实际开发需求。

DbContext 的生存期从创建实例时开始,并在释放实例时结束。 DbContext 实例旨在用于单个工作单元。这意味着 DbContext 实例的生存期通常很短。

使用 Entity Framework Core (EF Core) 时的典型工作单元包括:

  • 创建 DbContext 实例
  • 根据上下文跟踪实体实例。 实体将在以下情况下被跟踪
  • 正在从查询返回
  • 正在添加或附加到上下文
  • 根据需要对所跟踪的实体进行更改以实现业务规则
  • 调用 SaveChanges 或 SaveChangesAsync。 EF Core 检测所做的更改,并将这些更改写入数据库
  • 释放 DbContext 实例
注意事项:
1、使用后释放 DbContext 非常重要。这可确保释放所有非托管资源,并注销任何事件或其他挂钩,以防止在实例保持引用时出现内存泄漏。
2、DbContext 不是线程安全的。不要在线程之间共享上下文。请确保在继续使用上下文实例之前,等待所有异步调用。
3、EF Core 代码引发的 InvalidOperationException 可以使上下文进入不可恢复的状态。此类异常指示程序错误,并且不旨在从其中恢复。

在许多 Web 应用程序中,每个 HTTP 请求都对应于单个工作单元。这使得上下文生存期与请求的生存期相关,成为 Web 应用程序的一个良好默认值。

使用依赖关系注入配置 ASP.NET Core 应用程序。可以在 Startup.cs 文件的 ConfigureServices 方法中,用 AddDbContext 扩展方法将 EF Core 添加到此处进行配置。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    #region 配置MySQL数据库
    var connectionString = "server=数据库部署的服务器地址;user=数据库登录用户名;password=数据库登录密码;database=数据库名;charset=utf8";
    var serverVersion = new MySqlServerVersion(new Version(5, 7, 22));
    services.AddDbContext<customappdbcontext>(
        dbContextOptions => dbContextOptions
            .UseMySql(connectionString, serverVersion)
    );
    #endregion
}</customappdbcontext>

此示例将名为 CustomAppDbContext 的 DbContext 子类注册为 ASP.NET Core 应用程序服务提供程序(也称为依赖关系注入容器)中的作用域服务。上下文配置为使用 MySQL 数据库提供程序,并将从 ASP.NET Core 配置读取连接字符串。 在 ConfigureServices 中的何处调用 AddDbContext 通常不重要。

<strong>F12&#x8F6C;&#x5230; DbContext &#x7C7B;&#x7684;&#x5B9A;&#x4E49;&#xFF0C;&#x53D1;&#x73B0;&#x5176;&#x6709;&#x53C2;&#x6784;&#x9020;&#x51FD;&#x6570;&#x5B9A;&#x4E49;&#x5F62;&#x5F0F;&#x4E3A;&#xFF1A;</strong>

<strong>public DbContext([NotNullAttribute] DbContextOptions options);</strong>

CustomAppDbContext 类必须公开具有 DbContextOptions

public class CustomAppDbContext : DbContext
{
    public CustomAppDbContext(DbContextOptions<customappdbcontext> options) : base(options)//&#x8C03;&#x7528;&#x7236;&#x7C7B;&#x7684;&#x6784;&#x9020;&#x51FD;&#x6570;
    {
    }

    public DbSet<student> Student { get; set; }
}</student></customappdbcontext>

其中 Student 类如下所示:

public partial class Student
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime? JoinTime { get; set; }
    public int Sex { get; set; }
}

然后,CustomAppDbContext 可以通过构造函数注入在 ASP.NET Core 控制器或其他服务中使用。例如:

public class MyController : Controller
{
    private readonly CustomAppDbContext _context;

    public MyController(CustomAppDbContext context)//&#x6784;&#x9020;&#x51FD;&#x6570;
    {
        _context = context;
    }

    public JsonResult Index()
    {
        _context.Student.Add(new Student
        {
            Id = "10001",
            Name = "&#x5F20;&#x4E09;",
            JoinTime = DateTime.Now,
            Sex = 1
        });
        _context.SaveChanges();
        return new JsonResult("success");
    }
}

最终结果是为每个请求创建一个 CustomAppDbContext 实例,并传递给控制器,以在请求结束后释放前执行工作单元。

可以按照常规的 .NET 方式构造 DbContext 实例,例如,使用 C# 中的 new。可以通过重写 OnConfiguring方法或通过将选项传递给构造函数来执行配置。

1、重写 OnConfiguring 方法。

<strong>F12&#x8F6C;&#x5230; DbContext &#x7C7B;&#x7684;&#x5B9A;&#x4E49;&#xFF0C;&#x53D1;&#x73B0; OnConfiguring &#x65B9;&#x6CD5;&#x7684;&#x5B9A;&#x4E49;&#x5F62;&#x5F0F;&#x4E3A;&#xFF1A;</strong>

protected internal virtual void OnConfiguring(DbContextOptionsBuilder optionsBuilder);

DbContext 子类的代码示例如下所示:

public class NewCustomAppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql("server=&#x6570;&#x636E;&#x5E93;&#x90E8;&#x7F72;&#x7684;&#x670D;&#x52A1;&#x5668;&#x5730;&#x5740;;user=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x7528;&#x6237;&#x540D;;password=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x5BC6;&#x7801;;database=&#x6570;&#x636E;&#x5E93;&#x540D;;charset=utf8", new MySqlServerVersion(new Version(5, 7, 22)));
    }

    public DbSet<student> Student { get; set; }
}</student>

此种方式构造的 DbContext 实例在控制器方法中调用如下所示:

public class MyNewController : Controller
{
    public string Index()
    {
        using  var db = new NewCustomAppDbContext();
        var list = db.Student.ToList();
        return JsonConvert.SerializeObject(list);
    }
}

2、通过 DbContext 构造函数传递配置

通过此模式,我们还可以轻松地通过 DbContext 构造函数传递配置(如连接字符串)。例如:

public class NewCustomAppDbContext : DbContext
{
    private readonly string _connectionString;

    public NewCustomAppDbContext(string connectionString)
    {
        _connectionString = connectionString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql(_connectionString, new MySqlServerVersion(new Version(5, 7, 22)));
    }

    public DbSet<student> Student { get; set; }
}</student>

此种方式构造的 DbContext 实例在控制器方法中调用如下所示:

public class MyNewController : Controller
{
    public string Index()
    {
        using  var db = new NewCustomAppDbContext("server=&#x6570;&#x636E;&#x5E93;&#x90E8;&#x7F72;&#x7684;&#x670D;&#x52A1;&#x5668;&#x5730;&#x5740;;user=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x7528;&#x6237;&#x540D;;password=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x5BC6;&#x7801;;database=&#x6570;&#x636E;&#x5E93;&#x540D;;charset=utf8");
        var list = db.Student.ToList();
        return JsonConvert.SerializeObject(list);
    }
}

3、使用 DbContextOptionsBuilder 创建 DbContextOptions 对象

可以使用 DbContextOptionsBuilder 创建 DbContextOptions 对象,然后将该对象传递到 DbContext 构造函数。这使得为依赖关系注入配置的 DbContext 也能显式构造。例如:

public class DICustomAppDbContext:DbContext
{
    public DICustomAppDbContext(DbContextOptions<dicustomappdbcontext> optionsBuilder):base(optionsBuilder)
    {
    }

    public DbSet<student> Student { get; set; }
}</student></dicustomappdbcontext>

此种构造方式,在 Controller 中可以创建 DbContextOptions,并可以显式调用构造函数,代码如下所示:

public class MyDIController : Controller
{
    private readonly string _connectionString = "server=&#x6570;&#x636E;&#x5E93;&#x90E8;&#x7F72;&#x7684;&#x670D;&#x52A1;&#x5668;&#x5730;&#x5740;;user=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x7528;&#x6237;&#x540D;;password=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x5BC6;&#x7801;;database=&#x6570;&#x636E;&#x5E93;&#x540D;;charset=utf8";
    private readonly MySqlServerVersion _serverVersion = new MySqlServerVersion(new Version(5, 7, 22));

    public string Index()
    {
        var contextOptions = new DbContextOptionsBuilder<dicustomappdbcontext>()
            .UseMySql(_connectionString, _serverVersion)
            .Options;
        using var context = new DICustomAppDbContext(contextOptions);
        var list = context.Student.ToList();
        return JsonConvert.SerializeObject(list);
    }
}</dicustomappdbcontext>

某些应用程序类型(例如 ASP.NET Core Blazor)使用依赖关系注入,但不创建与所需的 DbContext 生存期一致的服务作用域。即使存在这样的对齐方式,应用程序也可能需要在此作用域内执行多个工作单元。例如,单个 HTTP 请求中的多个工作单元。

在这些情况下,可以使用 AddDbContextFactory 来注册工厂以创建 DbContext 实例。例如:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    #region &#x914D;&#x7F6E;MySQL&#x6570;&#x636E;&#x5E93;
    var connectionString = "server=&#x6570;&#x636E;&#x5E93;&#x90E8;&#x7F72;&#x7684;&#x670D;&#x52A1;&#x5668;&#x5730;&#x5740;;user=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x7528;&#x6237;&#x540D;;password=&#x6570;&#x636E;&#x5E93;&#x767B;&#x5F55;&#x5BC6;&#x7801;;database=&#x6570;&#x636E;&#x5E93;&#x540D;;charset=utf8";
    var serverVersion = new MySqlServerVersion(new Version(5, 7, 22));
    services.AddDbContextFactory<factorycustomappdbcontext>(
        dbContextOptions => dbContextOptions
            .UseMySql(connectionString, serverVersion)
    );
    #endregion
}</factorycustomappdbcontext>

FactoryCustomAppDbContext 类必须公开具有 DbContextOptions

public class FactoryCustomAppDbContext : DbContext
{
    public FactoryCustomAppDbContext(DbContextOptions<factorycustomappdbcontext> options) : base(options)
    {
    }

    public DbSet<student> Student { get; set; }
}</student></factorycustomappdbcontext>

然后,可以通过构造函数注入在其他服务中使用 DbContextFactory 工厂。最后,可以使用注入的工厂在服务代码中构造 DbContext 实例。例如:

public class MyFactoryController : Controller
{
    private readonly IDbContextFactory<factorycustomappdbcontext> _contextFactory;

    public MyFactoryController(IDbContextFactory<factorycustomappdbcontext> contextFactory)
    {
        _contextFactory = contextFactory;
    }

    public string Index()
    {
        using (var context = _contextFactory.CreateDbContext())
        {
            var list = context.Student.ToList();
            return JsonConvert.SerializeObject(list);
        }
    }
}</factorycustomappdbcontext></factorycustomappdbcontext>

请注意,以这种方式创建的 DbContext 实例并非由应用程序的服务提供程序进行管理,因此必须由应用程序释放。

所有 DbContext 配置的起始点都是 DbContextOptionsBuilder。可以通过以下三种方式获取此生成器:

每种配置方式的示例在本文上述内容中都进行了讲解和代码展示。无论生成器来自何处,都可以应用相同的配置。此外, 无论如何构造上下文,都将始终调用 OnConfiguring。这意味着即使使用 AddDbContext,OnConfiguring 也可用于执行其他配置。

每个 DbContext 实例都必须配置为使用 一个且仅一个数据库提供程序。(DbContext 子类型的不同实例可用于不同的数据库提供程序,但一个实例只能使用一个。)一个数据库提供程序要使用一个特定的 Use* 调用进行配置。

例如,若要使用 MySQL 数据库提供程序:

public class MySQLAppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql("&#x6570;&#x636E;&#x5E93;&#x8FDE;&#x63A5;&#x5B57;&#x7B26;&#x4E32;", new MySqlServerVersion(new Version(5, 7, 22)));
    }
}

例如,若要使用 SQL Server 数据库提供程序:

public class SQLServerApplicationDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("&#x6570;&#x636E;&#x5E93;&#x8FDE;&#x63A5;&#x5B57;&#x7B26;&#x4E32;");
    }
}

这些 Use* 方法是由数据库提供程序实现的扩展方法。 这意味着必须先安装数据库提供程序 NuGet 包,然后才能使用扩展方法。

EF Core &#x6570;&#x636E;&#x5E93;&#x63D0;&#x4F9B;&#x7A0B;&#x5E8F;&#x5E7F;&#x6CDB;&#x4F7F;&#x7528;&#x6269;&#x5C55;&#x65B9;&#x6CD5;&#x3002;&#x5982;&#x679C;&#x7F16;&#x8BD1;&#x5668;&#x6307;&#x793A;&#x627E;&#x4E0D;&#x5230;&#x65B9;&#x6CD5;&#xFF0C;&#x8BF7;&#x786E;&#x4FDD;&#x5DF2;&#x5B89;&#x88C5;&#x63D0;&#x4F9B;&#x7A0B;&#x5E8F;&#x7684; NuGet &#x5305;&#xFF0C;&#x5E76;&#x4E14;&#x5728;&#x4EE3;&#x7801;&#x4E2D;&#x5DF2;&#x6709; using Microsoft.EntityFrameworkCore;&#x3002;

下表包含常见数据库提供程序的示例。

数据库系统 配置示例 NuGet 程序包 SQL Server 或 Azure SQL .UseSqlServer(connectionString) Microsoft.EntityFrameworkCore.SqlServer Azure Cosmos DB .UseCosmos(connectionString, databaseName) Microsoft.EntityFrameworkCore.Cosmos SQLite .UseSqlite(connectionString) Microsoft.EntityFrameworkCore.Sqlite EF Core 内存中数据库 .UseInMemoryDatabase(databaseName) Microsoft.EntityFrameworkCore.InMemory PostgreSQL .UseNpgsql(connectionString) Npgsql.EntityFrameworkCore.PostgreSQL MySQL/MariaDB .UseMySql(connectionString) Pomelo.EntityFrameworkCore.MySql Oracle .UseOracle(connectionString) Oracle.EntityFrameworkCore

Entity Framework Core 不支持在同一 DbContext 实例上运行多个并行操作。这包括异步查询的并行执行以及从多个线程进行的任何显式并发使用。因此,始终立即 await 异步调用,或对并行执行的操作使用单独的 DbContext 实例。

当 EF Core 检测到尝试同时使用 DbContext 实例的情况时,你将看到 InvalidOperationException,其中包含类似于以下内容的消息:

<strong>A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be thread safe.</strong>

翻译成中文就是:

<strong>&#x5728;&#x4E0A;&#x4E00;&#x4E2A;&#x64CD;&#x4F5C;&#x5B8C;&#x6210;&#x4E4B;&#x524D;&#xFF0C;&#x5728;&#x6B64;&#x4E0A;&#x4E0B;&#x6587;&#x4E0A;&#x542F;&#x52A8;&#x4E86;&#x7B2C;&#x4E8C;&#x4E2A;&#x64CD;&#x4F5C;&#x3002;&#x8FD9;&#x901A;&#x5E38;&#x662F;&#x7531;&#x4E0D;&#x540C;&#x7EBF;&#x7A0B;&#x4F7F;&#x7528;&#x76F8;&#x540C;&#x7684;DbContext&#x5B9E;&#x4F8B;&#x5F15;&#x8D77;&#x7684;&#xFF0C;&#x4F46;&#x4E0D;&#x4FDD;&#x8BC1;&#x5B9E;&#x4F8B;&#x6210;&#x5458;&#x662F;&#x7EBF;&#x7A0B;&#x5B89;&#x5168;&#x7684;&#x3002;</strong>

当并发访问未被检测到时,可能会导致未定义的行为、应用程序崩溃和数据损坏。

使用异步方法,EF Core 可以启动以非阻挡式访问数据库的操作。但是,如果调用方不等待其中一个方法完成,而是继续对 DbContext 执行其他操作,则 DbContext 的状态可能会(并且很可能会)损坏。

应始终立即等待 EF Core 异步方法。

Original: https://www.cnblogs.com/iZOHC/p/16683364.html
Author: 张欧昊辰
Title: 002从零开始入门Entity Framework Core——DbContext生存期、配置和初始化

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/611077/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • myrocks复制中断问题排查

    mysql可以支持多种不同的存储引擎,innodb由于其高效的读写性能,并且支持事务特性,使得它成为mysql存储引擎的代名词,使用非常广泛。随着SSD逐渐普及,硬件存储成本越来越…

    数据库 2023年6月9日
    0102
  • 主从复制架构直接转换MGR(manual)

    IP port role info 192.168.188.81 3316 node1 master 192.168.188.82 3316 node2 slave1 192.16…

    数据库 2023年6月16日
    0221
  • vim+vundle配置

    Linux环境下写代码虽然没有IDE,但通过给vim配置几个插件也足够好用。一般常用的插件主要包括几类,查找文件,查找符号的定义或者声明(函数,变量等)以及自动补全功能。一般流程都…

    数据库 2023年6月9日
    089
  • windows bat

    windows bat windows bat netsh2-ipv4 新建文件夹 Windows 10 右下角时间显示时分秒 windows route 检测到以管理员权限运行 …

    数据库 2023年6月9日
    0102
  • Yapi安装配置(CentOs)

    环境要求 nodejs(7.6+)mongodb(2.6+)git 准备工作 清除yum命令缓存 sudo yum clean all 卸载低版本nodejs yum remove…

    数据库 2023年6月11日
    073
  • Rocksdb Compaction原理

    compaction主要包括两类:将内存中imutable 转储到磁盘上sst的过程称之为flush或者minor compaction;磁盘上的sst文件从低层向高层转储的过程称…

    数据库 2023年6月9日
    095
  • Java 函数式编程

    有且仅有一个未实现的非静态方法的接口叫做”函数式接口” interface IFactory<t> { T create(); } </t…

    数据库 2023年6月6日
    0120
  • 2 Java中 == 和 equals 和 hashCode 的区别

    ==是一个比较运算符; 若比较的是基本数据类型,则比较的是值; 若比较的是引用数据类型,则比较的是它们在内存中的内存地址。 说明:对象是存放在堆中,栈中存放的是对象的引用,因此==…

    数据库 2023年6月6日
    097
  • leetcode 637. Average of Levels in Binary Tree 二叉树的层平均值(简单)

    一、题目大意 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 示例 1: 输入:root = [3,…

    数据库 2023年6月16日
    077
  • 容器化 | 在 NFS 备份恢复 RadonDB MySQL 集群数据

    社区于上个月发布了 RadonDB MySQL Kubernetes v2.2.0,集群数据备份恢复的存储类型除了 S3,新增 NFS 存储。本文将为您演示如何进行 NFS 备份及…

    数据库 2023年5月24日
    0150
  • Component name “Login“ should always be multi-word

    在运行vue项目的时候,看到此提示 这是因为没有关闭elint提示的错误,在vue.config.js下添加代码 lintOnSave: false Original: https…

    数据库 2023年6月11日
    081
  • 2_JDBC

    使用客户端工具访问数据库, 需要手工建立连接, 输入用户名和密码登陆, 编写SQL语句, 点击执行, 查看操作结果(结果集或受行数影响) 在实际开发中, 当用户的数据发生改变时, …

    数据库 2023年6月11日
    059
  • 23种设计模式之策略模式

    文章目录 概览 策略模式的优缺点 策略模式的应用场景 策略模式的结构与实现 * 模式的结构 模式的实现 策略模式的扩展 总结 ; 概览 策略模式定义了一系列算法,并将每个算法封装起…

    数据库 2023年6月6日
    0118
  • 3. 视图-触发器-存储过程-索引

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月16日
    070
  • 分布式锁的实现

    什么是分布式锁? 为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用Java并发处理相关的API(如ReentrantLo…

    数据库 2023年6月6日
    0107
  • mysql基础语法_曾佳豪

    一、构建数据库、表和数据类型 [En] I. Building databases, tables and data types 1.建库 create database if n…

    数据库 2023年5月24日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球