【Entity Framework】 EF中DbContext类详解
一、概述
DbContext类是实体框架的重要组成部分。它是应用域或实例类与数据库交互的桥梁。
从上图可以看出DbContext是负责与数据交互作为对象的主要类。DbContext负责以下活动:
- EntitySet:DbContext包含映射到数据库表的所有实体的实体集(DbSet)。
- 查询(Querying):DbContext将Linq-To-Entities查询转换为SQL查询并将其发送到数据库。
- 更改跟踪(Change Tracking):跟踪实体在从数据库查询后发生的更改
- 持久数据(Persisting Data):它还根据实体的状态对数据库执行插入,更新和删除操作。
- 缓存(Caching): DbContext默认进行一级缓存。它存储在上下文类生命周期中已经被检索的实体。
- 管理关系(Manage Relationship): DbContext还使用DB-First或Model-First方法使用CSDL,MSL和SSDL或者使用Code-First方法使用流利的API来管理关系。
- 对象实现(Object Materialization): DbContext将原始表数据转换为实体对象。
二、DbContext生存期
DbContext
的生存期从创建实例时开始,并在释放实例时结束。DbContext
实例皆在用于单个工作单元。这意味着DbContext
实例的生存期通常很短。
工作单元将持续跟踪在可能影响数据库的业务事务中执行的所有操作。 当你完成操作后,它将找出更改数据库作为工作结果时需要执行的所有操作
使用Entity Framework Core(EF Core)时的典型工作单元包括:
-
创建
DbContext
实例 -
根据上下文根据实体实例。实体将在以下情况下被追踪
- 正在从查询返回
- 正在添加或附加到上下文中
-
根据需要对所追踪的实体进行更改以实现业务规则
-
调用
SaveChanges
或SaveChangesAsync
。EF Core检测所做的更改,并将这些更改写入数据库。 -
释放
DbContext
实例
- 使用后释放
DbContext
非常重要。这可确保释放所有非托管资源,并注销任何事件或其他挂钩,以防止在实例保持引用时出现内存泄露。DbContext
不是线程安全的。不要在线程之间共享上下文。请确保在继续使用上下文实例之前,等待所有异步调用。- EF Core 代码引发的
InvalidOperationException
可以使上下文进入不可恢复的状态。此类异常指示程序错误。
三、ASP.NET Core依赖关系注入中的DbContext
在许多Web应用程序中,每个HTTP请求都对应于单个工作单元。这使得上下文生存期与请求的生存期相关,成为Web应用程序的一个良好默认值。
使用依赖关系注入配置ASP.NET Core应用程序。可以使用Startup.cs
的ConfigureServices
方法中的AddDbContext
将EF Core添加到次配置。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}
此示例将名为 ApplicationDbContext
的 DbContext
子类注册为 ASP.NET Core 应用程序服务提供程序(也称为依赖关系注入容器)中的作用域服务。 上下文配置为使用 SQL Server 数据库提供程序,并将从 ASP.NET Core 配置读取连接字符串。 在 ConfigureServices
中的何处调用 AddDbContext
通常不重要。
ApplicationDbContext
类必须公开具有 DbContextOptions<ApplicationDbContext>
参数的公共构造函数。 这是将 AddDbContext
的上下文配置传递到 DbContext
的方式。 例如:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
四、使用"NEW"的简单的DbContext初始化
可以按照常规的 .NET 方式构造 DbContext
实例,例如,使用 C# 中的 new
。 可以通过重写 OnConfiguring
方法或通过将选项传递给构造函数来执行配置。 例如:
public class ApplicationDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
}
}
通过此模式,还可以轻松地通过 DbContext
构造函数传递配置(如连接字符串)。 例如:
public class ApplicationDbContext : DbContext
{
private readonly string _connectionString;
public ApplicationDbContext(string connectionString)
{
_connectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
}
或者,可以使用DbContextOptionsBuilder
创建DbContextOptions
对象,然后将该对象传递到DbContext
构造函数。这使得为依赖关系注入配置的DbContext
也能显示构造。
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
五、DbContextOptions
所有 DbContext配置的起始点都是DbContextOptionsBuilder
。可以通过三种方式获取此生成器:
- 在
AddDbContext
和相关方法中 - 在
OnConfiguring
中 - 使用
new
显示构造
上述各节显示了其中每个示例。 无论生成器来自何处,都可以应用相同的配置。 此外,无论如何构造上下文,都将始终调用 OnConfiguring
。 这意味着即使使用 AddDbContext
,OnConfiguring
也可用于执行其他配置。
六、DbContext类的方法
Entry
:获取DbEntityEntry
给定的实体。该条目提供访问更改实体的跟踪信息和操作。
SavaChange
:对已添加,已修改或已删除状态的实体的数据库执行INSERT,UPDATE或DELETE命令。
SaveChangesAsync
: SaveChanges()
的异步方法。
Set
: 创建一个DbSet
可以用来查询和保存实例的TEntity
。