第十节: EF的三种追踪实体状态变化方式(DBEntityEntry、ChangeTracker、Local)
一. 简介
我们在前面章节介绍EF基本增删改的时候,曾说过EF的SaveChanges()方法,会一次性的将所有的实体的状态变化统一提交到数据库,那么你是否想过EF的实体会有哪些状态变化呢?什么原因会导致其变化呢?我们怎么来追踪EF的实体变化呢?本章节以追踪EF实体状态变化的三种方式为线索,一一介绍上面疑问。
废不多说,还是先把整理的结论贴出来,然后配合代码来介绍。
1. EF的实体状态总共有5种:Added、Deleted、Modified、Detached、unChanged
①. unChanged:属性值与数据库中属性值相同,没有发生任何变化,首次查询出来的实体的状态值为unChanged
②. Modified:实体中的某些属性的值或所有属性值与数据库中的发生了变化
A:从数据库中查询出来的实体,直接改实体属性的值, 可以将实体状态改为 Modified。
B:自己创建的实体,必须先Attach一下,直接改实体属性的值,才可以将实体状态改为 Modified。
③. Added: 实体将由上下文跟踪,但是在数据库中还不存在,
Add()和 AddRange方法可以将实体状态变为:Added
④. Deleted:实体将由上下文跟踪并存在于数据库中,但是已被标记为在下次调用 SaveChanges 时从数据库中删除。
A:从数据库中查询出来的实体,通过Remove方法, 可以将实体状态改为 Deleted。
B:自己创建的实体,必须先Attach一下,然后Remove方法,才可以将实体状态改为 Deleted。
⑤. Detached: 调用AsNoTracking方法,取消实体状态追踪
2. 追踪方法一:DbEntityEntry 追踪单个实体的状态
①. db.Entry(XXX).State 来获取实体的状态
②. db.Entry(XXX).OriginalValues["txt1"] 可以获取属性的原始值
③. db.Entry(XXX).CurrentValues["txt1"] 可以获取属性的现在值
3. 追踪方法二:ChangeTracker 追踪EF上下文中所有实体的状态
①. db.ChangeTracker.Entries() 获取所有的实体状态变化 获取的是一个 IEnumerable<DbEntityEntry> 集合,遍历可以获取每个实体的状态变化
4. 追踪方法三:Local 获取单个实体状态发生增加、修改的实体集合(不含删除)
①. db.XXX.Local 获取的是XXX实体的集合
5. 删除状态和附加状态: AsNoTracking 和 Attach
二. 代码测试
1. 追踪方法一:DbEntityEntry 追踪单个实体的状态
{
Console.WriteLine("-------------------追踪方法一:DbEntityEntry 追踪单个实体的状态--------------------------");
//修改前
var data1 = db.TestInfor.FirstOrDefault();
DbEntityEntry stata1 = db.Entry(data1);
Console.WriteLine("实体状态为:" + stata1.State);
//修改后
data1.txt1 = "fk";
DbEntityEntry stata2 = db.Entry(data1);
Console.WriteLine("实体状态为:" + stata2.State);
Console.WriteLine("txt1的原始值为" + stata2.OriginalValues["txt1"]);
Console.WriteLine("txt1的现在值为" + stata2.CurrentValues["txt1"]);
}

分析:修改后实体状态由Unchanged→Modified了。
2. 追踪方法二:ChangeTracker 追踪EF上下文中所有实体的状态
{
Console.WriteLine("-------------------追踪方法二:ChangeTracker 追踪EF上下文中所有实体的状态--------------------------");
//1.增加操作
db.TestInfor.Add(new TestInfor()
{
id = Guid.NewGuid().ToString("N"),
txt1 = "",
txt2 = ""
});
//2. 删除操作
var data = db.TestInfor.FirstOrDefault();
db.TestInfor.Remove(data);
//3. 修改操作
var data2 = db.TestInfor.Where(u => u.id == "").FirstOrDefault();
data2.txt2 = "mr123";
//4. 另外一个实体的增加操作
db.TestInfor2.Add(new TestInfor2()
{
txt11 = "",
txt22 = ""
});
List<DbEntityEntry> entityList = db.ChangeTracker.Entries().ToList();
foreach (var item in entityList)
{
Console.WriteLine("实体状态为:" + item.State);
}
}

3. 追踪方法三:Local 获取单个实体状态发生增加、修改的实体集合(不含删除)
{
Console.WriteLine("-------------------追踪方法三:Local 获取单个实体状态发生增加、修改的实体集合(不含删除)--------------------------");
//1.增加操作
db.TestInfor.Add(new TestInfor()
{
id = Guid.NewGuid().ToString("N"),
txt1 = "",
txt2 = ""
});
//2. 删除操作
var data = db.TestInfor.FirstOrDefault();
db.TestInfor.Remove(data);
//3. 修改操作
var data2 = db.TestInfor.Where(u => u.id == "").FirstOrDefault();
data2.txt2 = "mr123";
//4. 另外一个实体的增加操作
db.TestInfor2.Add(new TestInfor2()
{
txt11 = "",
txt22 = ""
});
var EntityList = db.TestInfor.Local;
foreach (var item in EntityList)
{
Console.WriteLine("实体的值分别为:{0},{1},{2}", item.id, item.txt1, item.txt2);
}
}

分析:这里的Local获取的是单个DBSet,发生了增加或修改操作,最终的获取的是实体集合。
4. 删除状态追踪和附加状态追踪(AsNoTracking 和 Attach)
{
Console.WriteLine("-------------------删除状态和附加状态(AsNoTracking 和 Attach) --------------------------");
//以修改为例测试状态
{
//1. 带状态追踪
var item = db.TestInfor.FirstOrDefault();
item.txt2 = "mr333+" + Guid.NewGuid().ToString("N").Substring();
Console.WriteLine("实体的状态为:" + db.Entry(item).State);
int n = db.SaveChanges();
if (n > )
{
Console.WriteLine("修改成功");
}
else
{
Console.WriteLine("没有相应的实体需要修改");
}
}
{
//2. 取消状态追踪
var item = db.TestInfor.AsNoTracking().FirstOrDefault();
item.txt2 = "mr333+" + Guid.NewGuid().ToString("N").Substring();
Console.WriteLine("实体的状态为:" + db.Entry(item).State);
int n = db.SaveChanges();
if (n > )
{
Console.WriteLine("修改成功");
}
else
{
Console.WriteLine("没有相应的实体需要修改");
}
}
{
//3. 自己创建实体进行修改
TestInfor item = new TestInfor()
{
id = ""
};
db.TestInfor.Attach(item);
item.txt1 = "fk3456";
Console.WriteLine("实体的状态为:" + db.Entry(item).State);
int n = db.SaveChanges();
if (n > )
{
Console.WriteLine("修改成功");
}
else
{
Console.WriteLine("没有相应的实体需要修改");
}
}
}

第十节: EF的三种追踪实体状态变化方式(DBEntityEntry、ChangeTracker、Local)的更多相关文章
- ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪
ASP.NET MVC深入浅出(被替换) 一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...
- 第十四节: EF的三种模式(四) 之 原生正宗的 CodeFirst模式的默认约定
一. 简介 1. 正宗的CodeFirst模式是不含有edmx模型,需要手动创建实体.创建EF上下文,然后生成通过代码来自动映射生成数据库. 2. 旨在:忘记SQL.忘记数据库. 3. 三类配置:On ...
- 第七节: EF的三种事务的应用场景和各自注意的问题(SaveChanges、DBContextTransaction、TransactionScope)
一. 什么是事务 我们通俗的理解事务就是一系列操作要么全部成功.要么全部失败(不可能存在部分成功,部分失败的情况). 举一个事务在我们日常生活中的经典例子:两张银行卡(甲.乙),甲向乙转钱,整个过程需 ...
- 第十一节: EF的三种模式(一) 之 DBFirst模式(SQLServer和MySQL两套方案)
一. 简介 EF连接数据库有三种模式,分别是DBFirst.ModelFirst.CodeFirst,分别适用于不同的开发场景. 该章节,将主要介绍EF的DBFirst连接SQLServer数据库和M ...
- 第十三节: EF的三种模式(三) 之 来自数据库的CodeFirst模式
一. 简介 [来自数据库的Code First模式]实质上并不是CodeFirst模式,而是DBFirst模式的轻量级版本,在该模式中取消了edmx模型和T4模板,直接生成了EF上下文和相应的类,该模 ...
- EF的三种数据加载方式
EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Loading都是延迟加载. (一 ...
- 三种Singleton的实现方式
来源:http://melin.iteye.com/blog/838258 三种Singleton的实现方式,一种是用大家熟悉的DCL,另外两种使用cas特性来实现. public class Laz ...
- Request三种获取数据的方式
今天在做ajax请求后台代码时,发现ajax的方法都对,但就是请求不了后台代码,后来在同事帮助下才发现前台定义了两个相同参数导致请求出错. 下面记录一下request三种获取数据的方式: 1. Req ...
- Objective-C:三种文件导入的方式以及atomic和nonatomic的区别
一.三种文件导入的方式比较: 类的前项声明@class.import.include: 1.采用@class 类名的方式,它会告诉编译器有这么一个类,目前不需要知道它内部的实例变量和方法是如何定义 ...
随机推荐
- zabbix监控Oracle
可监控项 使用zabbix监控oracle数据库需要借助第三方的插件,目前使用较多的是orabbix.目前维护到了1.2.3版本.关于oracle自带的监控项目有以下几个: DB Version (i ...
- #020PAT 没整明白的题L1-009 N个数求和 (20 分)
后面的测试点过不去,两个错误一个超时. 目前未解决 L1-009 N个数求和 (20 分) 本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和 ...
- python之常用模块
python 常用模块 之 (subprocess模块.logging模块.re模块) python 常用模块 之 (序列化模块.XML模块.configparse模块.hashlib模块) pyth ...
- 文本分类实战(二)—— textCNN 模型
1 大纲概述 文本分类这个系列将会有十篇左右,包括基于word2vec预训练的文本分类,与及基于最新的预训练模型(ELMo,BERT等)的文本分类.总共有以下系列: word2vec预训练词向量 te ...
- Cookie Session 与Token
由于HTTP是一种无状态的协议,服务器端无法知道用户与客户端交互的状态,比如如果一个用于之前已经访问过该服务器,服务器无法知道该用户是第二次访问,Session和Cookie都是用来保存用户与后端服务 ...
- Python小数据池和字典操作
小数据池 #id 查看内存地址 #多个代码块可以使用小数据池 #一个代码块中有一个问题,就是重复使用 #数字 -5~256 #字符串 字符串 乘法总数长度不能超过20, 0,1除外 #不能有特殊字符 ...
- HDU-problem-1002-人类史上最大最好的希望事件-矩阵快速幂
Problem Description 作为CNCS的半壁江山,狗哥常常在宇宙中心邵阳眺望黄浦江,夜晚的星空总是迷人,有时候还能见到彗星滑落. 狗哥是幸运的,他在两秒钟内看到了十七颗彗星划过天际,作为 ...
- 【转】JAVA多线程实现的四种方式
原文地址:http://www.cnblogs.com/felixzh/p/6036074.html Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callabl ...
- (PAT)L2-004 这是二叉搜索树吗?(数据结构)
题目链接:https://www.patest.cn/contests/gplt/L2-004 一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点, 其左子树中所有结点的键值小于该结点的 ...
- 比sun.misc.Encoder()/Decoder()的base64更高效的mxBase64算法
package com.mxgraph.online; import java.util.Arrays; /** A very fast and memory efficient class to e ...