EF Core实体跟踪

ops/2025/1/17 22:09:07/

快照更改跟踪

实体类没有实现属性值改变的通知机制,EF Core是如何检测到变化的呢?

快照更改跟踪:首次跟踪一个实体的时候,EF Core 会创建这个实体的快照。执行SaveChanges()等方法时,EF Core将会把存储的快照中的值与实体的当前值进行比较。

实体的状态

  1. 已添加(Added):DbContext正在跟踪此实体,但数据库中尚不存在该实体。
  2. 未改变(Unchanged):DbContext正在跟踪此实体,该实体存在于数据库中,其属性值和从数据库中读取到的值一致,未发生改变。
  3. 已修改(Modified):DbContext正在跟踪此实体,并存在于数据库中,并且其部分或全部属性值已修改。
  4. 已删除(Deleted):DbContext正在跟踪此实体,并存在于数据库中,但在下次调用 SaveChanges 时要从数据库中删除对应数据。
  5. 已分离(Detached):DbContext未跟踪该实体。

SaveChanges()操作

  1. “已分离”和“未改变”的实体,SaveChanges()忽略;
  2. “已添加”的实体,SaveChanges() 插入数据库;
  3. “已修改”的实体,SaveChanges() 更新到数据库;
  4. “已删除”的实体,SaveChanges() 从数据库删除;

EntityEntry

使用DbContext的Entry()方法来获得实体在EF Core中的跟踪信息对象EntityEntry。EntityEntry类的State属性代表实体的状态,通过DebugView.LongView属性可以看到实体的变化信息。

测试:从数据库中查出3条记录,修改一条、删除一条、一条不动;再new两个对象,其中一个Add,另外一个不动。然后查看它们的EntityEntry。

 

static async Task Main(string[] args)
{using (MyDbContext ctx = new MyDbContext()){var items = ctx.Books.Take(3).ToArray();var a1 = items[0];var a2 = items[1];var a3 = items[2];var a4 = new Book { Name = "ASP.NET", Author = "阿明", Price = 25.5 };var a5 = new Book { Name = "WinForm", Author = "马腾", Price = 19.99 };a1.Price += 1;ctx.Remove(a2);ctx.Books.Add(a4);EntityEntry e1 = ctx.Entry(a1);EntityEntry e2 = ctx.Entry(a2);EntityEntry e3 = ctx.Entry(a3);EntityEntry e4 = ctx.Entry(a4);EntityEntry e5 = ctx.Entry(a5);Console.WriteLine("e1.State:" + e1.State);Console.WriteLine("e1.DebugView.LongView:" + e1.DebugView.LongView);Console.WriteLine("e2.State:" + e2.State);Console.WriteLine("e3.State:" + e3.State);Console.WriteLine("e4.State:" + e4.State);Console.WriteLine("e5.State:" + e5.State);}
}

结论

DbContext会根据跟踪的实体的状态,在SaveChanges()的时候,根据实体状态的不同,生成Update、Delete、Insert等SQL语句,来把内存中实体的变化更新到数据库中。

EF Core优化:AsNoTracking

  1. 如果通过DbContext查询出来的对象只是用来展示,不会发生状态改变,则可以使用AsNoTracking()来 “禁用跟踪”。
  2. 分别加AsNoTracking()和不加,分别查看一个对象修改后的EntityEntry 信息。
  3. 如果查询出来的对象不会被修改、删除等,那么查询时可以AsNoTracking(),就能降低内存占用。
static async Task Main(string[] args)
{using (MyDbContext ctx = new MyDbContext()){//正常查询var items1 = ctx.Books.Take(3).ToArray();foreach (var e in items1){Console.WriteLine(e.Name);}var a1 = items1[0];Console.WriteLine(ctx.Entry(a1).State);//调用AsNoTrackingvar items2 = ctx.Books.AsNoTracking().Take(3).ToArray();foreach (var e in items2){Console.WriteLine(e.Name);}var a2 = items2[0];a2.Price += 200;Console.WriteLine(ctx.Entry(a2).State);ctx.SaveChanges();}
}

实体状态跟踪的妙用

  1. 开发人员一般不需要关注实体状态的跟踪,让它在背后帮助我们工作即可。
  2. 有人利用状态跟踪的特点做一些小动作,我不推荐,但是要介绍。

常规更新需要先查询、再更新,两条SQL。

直接更新一条数据

static async Task Main(string[] args)
{using (MyDbContext ctx = new MyDbContext()){Book b = new Book { Id = 4 };//跟踪通过Id定位b.Author = "小王";var entry = ctx.Entry(b);entry.Property("Author").IsModified = true;Console.WriteLine(entry.DebugView.LongView);ctx.SaveChanges();}
}

直接删除一条数据

static async Task Main(string[] args)
{using (MyDbContext ctx = new MyDbContext()){Book b = new Book { Id = 4 };ctx.Entry(b).State = EntityState.Deleted;await ctx.SaveChangesAsync();}
}

注意

上面的技巧代码可读性、可维护性不强,而且使用不当有可能造成不容易发现的Bug。带来的性能提升也是微乎其微的,因此不推荐使用,知道即可。


http://www.ppmy.cn/ops/150932.html

相关文章

C# 多线程发展史(面试思路)

多线程技术 本身是为了 提高 cpu利用率 提高效率而生 因为 cpu分片机制 导致 多线程存在顺序与业务不符合情况 为了满足 正确的执行业务顺序 而诞生第一个要点线程同步 无论是控制主线程的同步等待 thread join task result task wait() 还是线程之间对于共享资源 同步的多种…

【MacOS】恢复打开系统设置的安全性的允许以下来源的应用程序的“任何来源”

在系统更新后,系统设置的安全性的允许以下来源的应用程序的“任何来源”可能会被修改为“来自APP开发者”。 操作步骤: So, I figured it out how to allow apps from anywhere. But learned its the order of operations on how to enable this optio…

STM32-Flash存储

目录 1.0 闪存模块组织 2.0 Flash基本结构 3.0 Flash解锁 4.0 指针访问存储器地址 5.0 程序存储器编程 6.0 选项字节 7.0 选项字节编程 8.0 选项字节擦除 9.0 电子签名 10.0 手册解读 定义: STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部…

Linux服务器网络丢包场景及解决办法

一、Linux网络丢包概述 在数字化浪潮席卷的当下,网络已然成为我们生活、工作与娱乐不可或缺的基础设施,如同空气般,无孔不入地渗透到各个角落。对于 Linux 系统的用户而言,网络丢包问题却宛如挥之不去的 “噩梦”,频繁…

智能物流升级利器——SAIL-RK3576核心板AI边缘计算网关设计方案(一)

近年来,随着物流行业智能化和自动化水平不断提升,数据的实时处理与智能决策成为推动物流运输、仓储管理和配送优化的重要手段。传统的集中式云平台虽然具备强大计算能力,但高延迟和带宽限制往往制约了物流现场的即时响应。为此,我…

nginx反向代理http 和 https(案例)

说明:在香港开了一台虚拟机,主要用于将来自国外访问的80和443代理到大陆IDC机房 (1) 定义80和443的upstream 211.155.82.174 是keepalive中VIP对应的公网IP(在国内访问www.playyx.com解析到211.155.82.174) upstream new_server…

网络安全的学习路径 (包括资源)快速学习

网络安全是一个多学科领域,涉及到技术、管理和法律等方面的知识。以下是详细的网络安全学习路径,从入门到高级,为你提供清晰的学习方向。 第一阶段:入门基础 在这阶段,你需要掌握基础的计算机知识和网络安全的基本概念…

Therabody 与Garmin联手,共同推进运动恢复与健康科技新突破

本次合作以数据整合、人工智能驱动的数字教练与科学研究为重点,旨在更好地了解科学恢复对运动表现的影响 (2025年1月13日,中国上海)全球健康领导者Therabody宣布与智能手表品牌Garmin佳明建立战略合作关系,共同致力于…