在EFCore中的CRUD
在EFCore中的CRUD
实体的几种状态
一个实体可能会会有以下几种状态:
Added: 实体在数据库中不存在。SaveChanges方法将发起INSERT语法。Unchanged:SaveChanges方法对这种状态的实体什么都不会做。当从数据库读取实体之后,实体就是这种状态。Modified: 实体中全部或者部分字段是这种状态时,SaveChanges方法将发起UPDATE语法。Deleted: 实体被标志位删除时,SaveChanges方法将发起DELETE语法。Detached: 实体没有被数据库上下文(database context)状态跟踪。
更改实体状态的方法
- 使用
Context.Entry:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//1. 修改实体
Student studentToDelete = new Student() { ID = id };
_context.Entry(studentToDelete).State = EntityState.Deleted;
await _context.SaveChangesAsync();
//2. 修改字段
//查询 id=1 的学生
var studentToUpdate = await _context.Students.SingleOrDefaultAsync(s => s.ID == 1);//EntityState=Unchanged
var studentEntry = _context.Entry(studentToUpdate);
//设置为修改状态
studentEntry.Property(s => s.LastName).IsModified = true;//EntityState=Modified
studentEntry.Property(s => s.FirstMidName).IsModified = true;
//保存更改
await _context.SaveChangesAsync();
- 使用
防止加载不必要的字段
BindAttribute:Bind["Course","Grade"] Student s。较适用于Creat。- 使用
TryUpdateModel,传入一组委托参数,指定要更新的字段。这个方法会从Form表单读取数据,较适用于Edit。 - 使用
View Model,适用于Creat和Edit场景。做法:将view model 作为类型参数,接收数据,然后将其所有属性复制(可使用AutoMapper)到要更改的类实例中,使用_context.Entry方法将实体状态更改为Unchanged,然后再逐个将需要应用修改的属性状态IsModified改为true。最终保存到数据库。
主要
方法1 不适用于Edit方法,Bind会生成一个实例,将所有字段设置状态为Modified,未指定的字段会被清空。对于Edit方法,推荐先读取,再使用TryUpdateModel
增删改
1. 先读实体再修改
1 | [HttpPost, ActionName("Delete")] |
1 | [HttpPost, ActionName("Edit")] |
2. 先创建实体再修改
1 | [HttpPost] |
1 | public async Task<IActionResult> Edit(int id, [Bind("ID,EnrollmentDate,FirstMidName,LastName")] Student student) |
3. 使用ViewModel
创建一个具有几个需要更改属性的 `ViewModel`
查询
No-tracking查询HttpGet方法,在上下文生命周期内(默认是Scoped),不需要修改任何实体,不用通过多个查询加载导航属性- 需要查询大量数据,仅有少量需要修改,禁用跟踪能大幅提高效率。在需要更新数据之前,先查询这些少量的数据,再更新。
- 前面已经查询出对应数据,上下文已经跟踪该数据,但想使用
attach方式更新该数据。如果未禁用跟踪,无法以这种方式更新
跟踪查询(默认方式)
在上下文生命周期内(默认是
Scoped),数据会缓存,并且一直与数据库同步。
其他
- 数据库连接什么时候释放
数据库上下文是由DI注入,AddDbContext默认生命周期为Scope,生命周期之后,最终会释放数据库连接等资源。Scope意味着一次请求结束,生命周期结束。为什么?这里的Scope很有可能是HttpContext.RequestServices这个ServiceProvider创建的,或者其子ServiceProvider创建的,而HttpContext每次请求结束会释放,so… - 多个修改之后
SaveChanges,EFCore 隐式实现事务。