《ASP.NET Core技术内幕与项目实战》精简集-EFCore2.8:EFCore7的重磅更新-批量操作

本节内容,为补充内容,部分类型涉及5.1和5.2,P129-P134。主要NuGet包:

 

 一、实体更改跟踪

EFCore默认采用“快照更改跟踪”,会对“通过DbContext上下文查询出来的所有实体对象”进行跟踪,首次跟踪时,EFCore会为每个实体创建快照。通过对比当前值和快照值,就可以确定实体的当前状态,当执行SaveChanges时,会根据实体的状态,进行相应的数据库操作,并且跟踪的实体与发送到数据库的更改保持同步。状态跟踪有以下5种可能:

  • Added状态,SaveChanges时插入数据库
  • Deleted状态,SaveChanges时从数据库删除
  • Modified状态,SaveChanges时将修改更新到数据库
  • Unchanged状态,值为发生改变,SaveChanges时忽略
  • Detached状态,上下文未跟踪,SaveChanges时忽略

 

1、获取指定实体对象的跟踪信息

//ctx.Entry()方法,可获取指定对象的跟踪信息对象EntityEntry
var books = ctx.Books.Take(3).ToArray();
var book1 = books[0];
book1.Title = "xyz";
EntityEntry entry1 = ctx.Entry(book1);
Console.WriteLine(entry1.State); //结果为Modified
Console.WriteLine(entry1.DebugView.LongView);//打印详细的跟踪信息

//DebugView.LongView打印的结果如下
=======================
Book {Id: 1} Modified
  Id: 1 PK
  Price: 25
  Title: 'xyz' Modified Originally 'abc'
=======================

 

2、禁用跟踪AsNoTracking

EFCore对实体进行更改跟踪,要建立快照,进行当前值和快照值的对比,是比较消耗资源的。如果只是查询数据,不会发生状态改变,可以通过“禁用跟踪”,提升查询性能。

//禁用跟踪
var books_Tracking = ctx.Books.AsNoTracking().Take(3).ToArray();
var book1 = books_Tracking[0];
book1.Title = "xyz";
var entry2 = ctx.Entry(book1); 
Console.WriteLine(entry2.State); //结果为Detached

 

3、直接修改和删除

EFCore进行修改和删除操作时,需要先查询出指定数据,然后再进行修改或删除,编译为SQL时,首先会执行SELECT语句,然后再执行UPDATE或者DELETE,需要两句SQL。如果执行SQL,我们可以直接执行【UPDATE T_Book SET Title="xyz" WHERE Id=1】,效率更高。利用状态跟踪机制,我们可以让EFCore像SQL一样,直接进行更新或删除操作,不需要先查询再修改或删除。

//直接更新实体
var book1 = new Book { Id = 1 };
book1.Title = "xyz";
var entry1 = ctx.Entry(book1);
entry1.Property("Title").IsModified= true;
Console.WriteLine(entry1.DebugView.LongView);
ctx.SaveChanges();

//直接删除实体
var book2 = new Book{ Id = 1 };
ctx.Entry(book2).State = EntityState.Deleted;
ctx.SaveChanges();

 

 

 

二、EFCore7的批量修改

由于涉及实体的状态跟踪,如果进行数据库的批量操作时,如批量更新、批量删除等,需要一条一条进行,等于删除100条记录,需要执行100次DELETE,效率非常低,所以EFCore的批量操作一直被吐槽。批量操作提案,已被提出多年,但EFCore7之前,一直处于讨论状态,讨论核心主要是状态跟踪的问题。EFCore7终于带来了批量更新和批量删除(批量新增依旧没有),批量操作时,实体的跟踪状态与数据库更改不会同步,也就是说批量更新或删除的实体,是没有状态跟踪的,所以,之前几年讨论是为了啥?!如果执行完批量更新或删除后,如果要使用这些数据,应该再重新查询一次,这样可以建立状态跟踪。

 

1、批量删除ExcuteDelete/ExcuteDeleteAsync

//批量删除指定条件
ctx.Books.Where(b=>b.Id <= 2).ExecuteDelete();
//删除所有
await ctx.Books.ExecuteDeleteAsync();

//注意,如果数据表有删除约束条件,应该在删除主体前,先删除依赖项

 

2、批量更新ExcuteUpdate/ExcuteUpdateAsync

//批量更新所有,只更新一个属性
//ctx.Books.ExecuteUpdate(b => b.SetProperty(b=>b.Price,b=>b.Price + 50));

//批量更新指定条件,更新多个属性
await ctx.Books.Where(b => b.Price >= 50).ExecuteUpdateAsync(b=>b
    .SetProperty(b=>b.Title,"SameName")
    .SetProperty(b=>b.Price,b=>b.Price - 50)
);

 

 

 

特别说明:
1、本系列内容主要基于杨中科老师的书籍《ASP.NET Core技术内幕与项目实战》及配套的B站视频视频教程,同时会增加极少部分的小知识点
2、本系列教程主要目的是提炼知识点,追求快准狠,以求快速复习,如果说书籍学习的效率是视频的2倍,那么“简读系列”应该做到再快3-5倍

 

posted @ 2022-11-20 21:33  functionMC  阅读(747)  评论(0编辑  收藏  举报