实体状态 快照更改跟踪 首次跟踪一个实体的时候,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); } } }