实体状态 快照更改跟踪 首次跟踪一个实体的时候,EF Core会创建这个实体的快照。执行SaveChanges()等方法时,EF Core将会把存储在快照中的值与实体的当前值进行比较。 和DbContext有关系的实体、类都会生成快照。
实体的状态 已添加(Added):DbContext正在跟踪此实体,但数据库中尚不存在该实体。 未改变(Unchanged):DbContext正在跟踪此实体,该实体存在于数据库中,其属性值和从数据库中读取到的值一致,未发生改变。 已修改(Modified):DbContext正在跟踪此实体,并存在于数据库中,并且其部分或全部属性值已修改。 已删除(Deleted):DbContext正在跟踪此实体,并存在于数据库中,但在下次调用SaveChanges时要从数据库中删除对应数据。 已分离(Detached):DbContext未跟踪该实体。
查询实体状态 使用DbContext的Entry()方法来获取实体在EF Core的跟踪信息对象EntityEntry。EntityEntry类的State属性代表实体的状态,通过DebugView.LongView属性可以看到实体的变化信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 static async Task Main(string[] args) {             using (var ctx = new MyDbContext()) {                 var items = ctx.Articles.Take(5).ToArray();                 var a1 = items[0];                 var a2 = items[1];                 var a3 = items[2];                 var a4 = new Article() { Title = "ddd", Message = "xxxxxxxxxxx" };                 var a5 = new Article() { Title = "阿斯拉达覅见哦", Message = "送到哪给下次" };                 a2.Title = "WBG 0:3 不敌 T1";                 ctx.Articles.Remove(a3);                 ctx.Articles.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);                 Console.WriteLine(e2.DebugView.LongView);                 Console.WriteLine(e3.State);                 Console.WriteLine(e4.State);                 Console.WriteLine(e5.State);                 ctx.SaveChanges();             }          } 
 
结论 DbContext会根据跟踪的实体的状态,在SaveChanges()的时候,根据实体状态的不同,生成Update、Delete、Insert等SQL语句,来把内存中实体的变化更新到数据库。
AsNoTracking 如果通过DbContext查询出来的对象只是用来展示,不会发生状态改变,则可以使用AsNoTracking()来“禁用跟踪”,可以降低内存占用。
1 2 3 4 5 6 7 8 static async Task Main(string[] args) {             using (var ctx = new MyDbContext()) {                 var items = ctx.Articles.AsNoTracking().Take(5).ToArray();                 foreach (var item in items) {                     await Console.Out.WriteLineAsync(item.Title);                 }             }          }