EF ASP.NET MVC中HttpPost方法内实体未提交却同步值的问题
问题原因与解决方案
这其实是Entity Framework的变更跟踪机制在背后起作用,很容易让人踩坑!我来给你拆解清楚:
当你第一次执行db.Student.Where(...).SingleOrDefaultAsync()获取model1时,EF的DbContext会把这个实体对象存入它的内存缓存,并且开启对这个对象的状态跟踪。所以哪怕你只是修改了model1.Type但还没调用SaveChanges(),DbContext已经默默记录下了这个实体的属性变更。
重点来了:当你第二次查询同一个StudentGuid的model2时,EF不会再去数据库里重新读取数据——它会直接返回内存缓存里那个已经被修改过的实体实例!说白了,model1和model2其实是同一个对象的引用,你修改其中一个的属性,另一个自然会跟着变,因为它们根本就是同一个东西。
下面给你几个解决思路,按需选择:
- 如果想每次查询都从数据库取最新数据:在查询时加上
AsNoTracking(),这样EF不会把查询结果加入跟踪缓存,每次都会走数据库:
Student model2 = await db.Student.AsNoTracking().Where(s => s.StudentGuid.ToString() == id).SingleOrDefaultAsync();
- 如果只是想获取实体的原始数据库值:不需要重新查询,直接通过
DbContext.Entry获取原始值即可:
var originalType = db.Entry(model1).OriginalValues["Type"];
- 如果需要两个完全独立的实体实例:先把
model1从DbContext的跟踪中分离,再查询model2:
db.Entry(model1).State = EntityState.Detached; Student model2 = await db.Student.Where(s => s.StudentGuid.ToString() == id).SingleOrDefaultAsync();
补充一句:EF的变更跟踪是为了减少重复查询、优化性能,同时保证批量提交变更的效率,但这种“复用内存实例”的特性确实容易在不注意的时候造成困惑,根据你的业务场景选对应的方案就好~
内容的提问来源于stack exchange,提问作者Hisham Aburass
相关产品推荐
相关产品推荐

