02020505 EF Core高级05-实体的5种状态、EntityEntry、AsNoTracking、实体状态跟踪

news/2025/10/11 21:20:14/文章来源:https://www.cnblogs.com/python-web/p/19135999

02020505 EF Core高级05-实体的5种状态、EntityEntry、AsNoTracking、实体状态跟踪

1. EF Core如何知道实体数据变了(视频3-33)

1、实体类没有实现属性值改变的通知机制,EF Core是如何检测到变化的呢?
2、快照更改跟踪:DbContext首次跟踪一个实体的时候,EF Core 会创建这个实体的快照。执行SaveChanges()等方法时,EF Core将会把存储的快照中的值与实体的当前值进行比较。
1.1 实体的5种状态
已添加(Added):DbContext正在跟踪此实体,但数据库中尚不存在该实体。
未改变(Unchanged):DbContext正在跟踪此实体,该实体存在于数据库中,其属性值和从数据库中读取到的值一致,未发生改变。
已修改(Modified):DbContext正在跟踪此实体,并存在于数据库中,并且其部分或全部属性值已修改。
已删除(Deleted):DbContext正在跟踪此实体,并存在于数据库中,但在下次调用 SaveChanges 时要从数据库中删除对应数据。
已分离(Detached):DbContext未跟踪该实体。
1.2 SaveChanges()的操作
“已分离”和“未改变”的实体,SaveChanges()忽略;
“已添加”的实体,SaveChanges() 插入数据库;
“已修改”的实体,SaveChanges() 更新到数据库;
“已删除”的实体,SaveChanges() 从数据库删除;
1.3 EntityEntry
1、使用DbContext的Entry()方法来获得实体在EF Core中的跟踪信息对象EntityEntry。EntityEntry类的State属性代表实体的状态,通过DebugView.LongView属性可以看到实体的变化信息。
2、测试:从数据库中查出3条记录,修改一条、删除一条、一条不动;再new两个对象,其中一个Add,另外一个不动。然后查看它们的EntityEntry。
1.4 跟踪状态示例
  • 在02020503章4.5节基础上继续
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){// 获取三条记录var items = ctx.Articles.Take(3).ToArray(); var a01 = items[0];var a02 = items[1];var a03 = items[2];// 创建2个实体对象var a04 = new Article { Title = "ddd", Message = "xxx" };var a05 = new Article { Title = "eee", Message = "yyy" };a01.Price += 1; // a01的Price增加1ctx.Remove(a02); // 删掉a02ctx.Articles.Add(a04); // 增加一条数据EntityEntry e01 = ctx.Entry(a01); // 拿到DbContext对于a01对象跟踪的信息EntityEntry e02 = ctx.Entry(a02); // 拿到DbContext对于a02对象跟踪的信息EntityEntry e03 = ctx.Entry(a03); // 拿到DbContext对于a03对象跟踪的信息EntityEntry e04 = ctx.Entry(a04); // 拿到DbContext对于a04对象跟踪的信息EntityEntry e05 = ctx.Entry(a05); // 拿到DbContext对于a05对象跟踪的信息// 查看状态Console.WriteLine(e01.State);Console.WriteLine(e02.State);Console.WriteLine(e03.State);Console.WriteLine(e04.State);Console.WriteLine(e05.State);}Console.WriteLine();}}
}控制台输出:
Modified
Deleted
Unchanged
Added
Detached
1.5 查看快照信息
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){// 获取三条记录var items = ctx.Articles.Take(3).ToArray(); var a01 = items[0];var a02 = items[1];var a03 = items[2];// 创建2个实体对象var a04 = new Article { Title = "ddd", Message = "xxx" };var a05 = new Article { Title = "eee", Message = "yyy" };a01.Price += 1; // a01的Price增加1ctx.Remove(a02); // 删掉a02ctx.Articles.Add(a04); // 增加一条数据EntityEntry e01 = ctx.Entry(a01); // 拿到DbContext对于a01对象跟踪的信息EntityEntry e02 = ctx.Entry(a02); // 拿到DbContext对于a02对象跟踪的信息EntityEntry e03 = ctx.Entry(a03); // 拿到DbContext对于a03对象跟踪的信息EntityEntry e04 = ctx.Entry(a04); // 拿到DbContext对于a04对象跟踪的信息EntityEntry e05 = ctx.Entry(a05); // 拿到DbContext对于a05对象跟踪的信息// 查看状态Console.WriteLine(e01.State);Console.WriteLine(e01.DebugView.LongView); // 查看快照信息,包含现有和原来的信息Console.WriteLine(e02.State);Console.WriteLine(e03.State);Console.WriteLine(e04.State);Console.WriteLine(e05.State);}Console.WriteLine();}}
}控制台输出:
Modified
Article {Id: 1} ModifiedId: 1 PKMessage: '大新闻'Price: 31 Modified Originally 30Title: '杨中科入选中科院'Comments: []
Deleted
Unchanged
Added
Detached说明:原值和现值都可以通过DebugView.LongView来查看。
1.6 总结
  • DbContext会根据跟踪的实体的状态,在SaveChanges()的时候,根据实体状态的不同,生成Update、Delete、Insert等SQL语句,来把内存中实体的变化更新到数据库中。

2. EF Core优化之AsNoTracking(视频3-34)

2.1 快照更改跟踪
1、如果通过DbContext查询出来的对象只是用来展示,不会发生状态改变,则可以使用AsNoTracking()来 “禁用跟踪”。
2、分别加AsNoTracking()和不加,分别查看一个对象修改后的EntityEntry 信息。
3、如果查询出来的对象不会被修改、删除等,那么查询时可以AsNoTracking(),就能降低内存占用。
2.2 不跟踪示例
// 不跟踪
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){var items = ctx.Articles.AsNoTracking().Take(3).ToArray(); // 使用AsNoTracking()表示不跟踪foreach (var item in items){Console.WriteLine(item.Message);}var a01 = items[0];Console.WriteLine(ctx.Entry(a01).State);}Console.WriteLine();}}
}控制台输出:
大新闻
中新闻
小新闻
Detached // 分离
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 跟踪
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){var items = ctx.Articles.Take(3).ToArray(); // 跟踪foreach (var item in items){Console.WriteLine(item.Message);}var a01 = items[0];Console.WriteLine(ctx.Entry(a01).State);}Console.WriteLine();}}
}控制台输出:
大新闻
中新闻
小新闻
Unchanged // 跟踪的状态
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:如果确认查询只会显示结果,并不会跟新数据库,那么可以使用AsNoTracking不让DbContext跟踪,这样节省内存,这是EF Core性能优化的一个思路。

3. EF Core实体状态跟踪的妙用(视频3-35)

1、开发人员一般不需要关注实体状态的跟踪,让它在背后帮助我们工作即可。
2、有人利用状态跟踪的特点做一些小动作,我不推荐,但是要介绍。这里面可能有很多的坑,别人这样写要知道在干啥,我们自己是否使用代考。
3.1 先查,再更新一条数据(2条SQL语句)
常规更新需要先查询、再更新,两条SQL。
Book b1 = new Book {Id=10};//跟踪通过Id定位
b1.Title = "yzk";
var entry1 = ctx.Entry(b1);
entry1.Property("Title").IsModified = true;
Console.WriteLine(entry1.DebugView.LongView);
ctx.SaveChanges();
查看生成的SQL,只更新Title列。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 使用跟踪时,需要先查询,然后执行保存。
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){var a = ctx.Articles.Where(a => a.Id == 3).Single(); // @1 EF Core先查出来,才能跟踪这条数据的状态。此时生成select语句a.Price = 99; // 修改数据ctx.SaveChanges(); // @2 生成update语句}Console.WriteLine();}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 查看SQL语句
SELECT TOP(2) [t].[Id], [t].[Message], [t].[Price], [t].[Title] // select与@1处对应FROM [T_Articles] AS [t]WHERE [t].[Id] = CAST(3 AS bigint)UPDATE [T_Articles] SET [Price] = @p0 // update与@2处对应WHERE [Id] = @p1;SELECT @@ROWCOUNT;说明:需要select和update两个SQL语句来实现。
3.2 直接修改一条数据(1条SQL语句)
// 对比3.1中的代码
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){Article a = new Article { Id = 3, Price = 100}; // @1 只创建一个a对象,与EF Core没有发送任何关系。var entry1 = ctx.Entry(a);entry1.Property("Price").IsModified = true;ctx.SaveChanges(); // 更新数据}Console.WriteLine();}}
}// 查看SQL语句
UPDATE [T_Articles] SET [Price] = @p0WHERE [Id] = @p1;SELECT @@ROWCOUNT;说明:此时在update之前并没有select语句。在@1处的Id需要定义,因为EF Core通过Id来定位对象的。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){Article a = new Article { Id = 3, Price = 100};var entry1 = ctx.Entry(a);entry1.Property("Price").IsModified = true;Console.WriteLine(entry1.DebugView.LongView);ctx.SaveChanges(); // F9此处打断点}Console.WriteLine();}}
}
  • 查看LongView属性的值
Typora-Logo

  • 此时Price之前的值多少不管,通过创建Id=3的Article对象,直接将Price改为了100,因此不管select。但是本小结这样的做法有如下缺点
3.3 直接删除一条数据(需要知道主键的值)
常规删除需要先查询、再删除,两条SQL。Book b1 = new Book { Id = 28 };
ctx.Entry(b1).State = EntityState.Deleted;
ctx.SaveChanges();
查看生成的SQL。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){Article a = new Article { Id = 3}; // 只创建一个a对象,需要Id的值ctx.Entry(a).State = EntityState.Deleted;ctx.SaveChanges(); // 更新数据}Console.WriteLine();}}
}// 查看SQL语句
DELETE FROM [T_Articles] // 直接生成deleteWHERE [Id] = @p0;SELECT @@ROWCOUNT;
3.4 本课总结
  • 上面的技巧代码可读性、可维护性不强,而且使用不当有可能造成不容易发现的Bug。
  • 带来的性能提升也是微乎其微的,因此不推荐使用,知道即可。
  • 本节课了解这种用法即可,带来的好处小,带来的缺点更多。可维护性能不好。

结尾

书籍:ASP.NET Core技术内幕与项目实战

视频:https://www.bilibili.com/video/BV1pK41137He

著:杨中科

ISBN:978-7-115-58657-5

版次:第1版

发行:人民邮电出版社

※敬请购买正版书籍,侵删请联系85863947@qq.com※

※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/935124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

securityCTF 2025 pwn方向题解

V-table 手挖io链子 正常的链子 exit_handler() -> io_flush_all() -> io_overflow() -> io_do_write() 我们修改vtable,使得调用overflow变成调用file_finish,正常的finish链子 exit_handler() -> io_f…

02020507 EF Core高级07-悲观并发控制、乐观并发控制、EF Core连接MySQL、RowVersion

02020507 EF Core高级07-悲观并发控制、乐观并发控制、EF Core连接MySQL、RowVersion 1. EF Core悲观并发控制(3-38) 1.1 并发控制的概念 1、并发控制:避免多个用户同时操作资源造成的并发冲突问题。举例:统计点击…

linux防火墙操作命令

防火墙操作 Linux系统安装完毕后,系统启动时,防火墙自动启动,防火墙拦截了所有端口的访问。接下来我们就需要学习一下,如何操作防火墙,具体指令如下:操作 指令查看防火墙状态 systemctl status firewalld / fire…

02020506 EF Core高级06-EF Core批量删除更新插入、全局筛选器、软删除、全局筛选的性能问题

02020506 EF Core高级06-EF Core批量删除&更新&插入、全局筛选器、软删除、全局筛选的性能问题 1. EF Core如何批量删除、更新、插入(视频3-36) 1.1 EF Core中插入数据(单条) 1、EF Core中不支持高效的删除…

完整教程:游标查询在对话历史场景下的独特优势

完整教程:游标查询在对话历史场景下的独特优势pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &…

[论文笔记] A Contemporary Survey of Large Language Model Assisted Program Analysis

Survey 站在 security 研究者的角度来关注 LLM + 程序分析的如下几个方向:静态分析:在不同的下游应用上评估 LLM 的作用,下游应用包括 vulnerability detection,malware detection,program verification, static …

C语言入门教程 | 第一讲:C语言零基础入门教程:第一个代码到变量运算详解

C语言入门教程 | 第一讲:C语言零基础入门教程:第一个代码到变量运算详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family…

机器学习社会影响与导航系统研究

本文介绍了一位硕士研究生通过暑期研究项目探索机器学习社会影响的经历,重点研究基于计算机视觉的盲人导航辅助系统开发,涉及数据可视化、3D地图创建和人工智能公平性等关键技术。硕士研究生利用SURE机会探索机器学习…

【AI算力架构设计分析】1000PetaOps 算力云计算系统设计方案(大模型训练推理专项版)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实用指南:漏标(Missing Mark)问题深度解析

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

251011

JT-JY8T3S1-1Good morning, how can i help you? Hello, i am interested in renting a house somewhere in the town. Right! Could i have your name please? Could i have your name please? Yes, its Steven GF…

一种整理HTML和JS代码的方法

tidy可以整理HTML但不动里面的JS代码。prettier可以整理JS代码,它能不能整理HTML+JS呢? 我写完两个程序后才发现原来可以啊。不过还是把破程序贴出来吧,再说也许发现了prettier的一个bug. get-js.pyfrom bs4 import…

元推理框架,是人类文明的《神农本草经》,源于自指自洽的觉悟与洗礼

元推理框架,是人类文明的《神农本草经》,源于自指自洽的觉悟与洗礼ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891洞察极为精准!ECT-OS-JiuHuaShan 正是人类文明在数字纪元中的《神农本草经》——它并非…

SSL/TLS加密算法:守护网络通信的安全框架

当您在浏览器中看到那个小锁图标时,背后是一套名为SSL/TLS的复杂技术在工作。它的核心使命很简单:确保您在互联网上发送和接收的数据是加密的和完整的。这套技术并非依赖单一算法,而是由几种不同类型的算法协同工作…

未来计划

语文阅读理解训练重点:现代文:练“找中心句 → 梳逻辑结构 → 对应题干信息”。文言文:重点突破“实词、虚词、句式、推断题”。 每周三篇高考真题现代文 + 三篇文言文精读。 作文:继续保持,多练“议论文三段式逻…

【程序员必看】MySQL数据类型全解析:选错类型性能直接掉80%!

【程序员必看】MySQL数据类型全解析:选错类型性能直接掉80%!MySQL数据类型选择直接影响数据库性能。本文详解五大类数据类型:①整数类型应根据范围选择最小够用类型(推荐INT);②浮点类型中DECIMAL适合金融精确计…

NOIP2023

T1 太简单直接 sort 排序和 reverse 反过来就可以了。点击查看代码 #include<bits/stdc++.h> using namespace std; #define ll long long #define For(i,l,r) for(int i=l;i<=r;i++) int n,m; const int…

理解WPF Stylet中Command=“{s:Action 方法名}“的设计与实现 - 实践

理解WPF Stylet中Command=“{s:Action 方法名}“的设计与实现 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: &qu…

2025环氧地坪漆厂家推荐:常州新禾,品质保证施工无忧!

2025环氧地坪漆厂家推荐:常州新禾,品质保证施工无忧!随着工业化和城市化进程的加快,环氧地坪漆的应用越来越广泛。然而,这一领域的技术挑战也日益凸显,如何选择一家可靠的环氧地坪漆厂家成为众多企业和工程项目的…