阅读目录:数据库
1、什么是Identity map模式缓存
2、关于Identity map模式的验证示例ide
3、Unit of Work 模式spa
4、总结和注意的问题.net
Identity map是EF获取和缓存数据的模式。
Identity map模式指的是任何数据都只会被加载一次,以map的形式缓存,以惟一的identity来再次获取这些数据。
在EF中,就是在一个Context的生命周期中,全部查询过的数据都会缓存到Context的local中缓存。当再次访问这些数据的时候,就会以主键(identity)从缓存中获取这些数据。3d
看看下面这段代码运行的结果:code
using (var context = new SchoolContext()) { result1 = context.Students.ToList(); result1[0].Age = -1; result2 = context.Students.ToList(); var s1 = context.Students.First(s => s.Id == 1); var s2 = context.Students.First(s => s.Id == 1); var s3 = context.Students.First(s => s.Id == 3); var s4 = context.Students.First(s => s.Id == 3); Debug.Assert(ReferenceEquals(s1, s2)); Debug.Assert(ReferenceEquals(s3, s4)); }
运行以后,会发现s1和s2是同一个引用,s3和s4也是同一个引用。
缘由就是在Identity map模式来讲,对于惟一的主键,返回的必然是同一个对象。对象
再来看一个更加有趣的例子blog
public IEnumerable<Student> GetStudents() { List<Student> result1; List<Student> result2; using (var context = new SchoolContext()) { result1 = context.Students.ToList(); result1[0].Age = -1; result2 = context.Students.ToList(); } return result2; }
实际的数据库中的result1[0].Age是18,若是修改Age是-1, 再次执行context.Students.ToList(), 返回数据的Age并非数据库中的18,而是-1.生命周期
可是根据MiniProfiler的监控结果,EF的确访问了2次数据库
从这里,得出的结论是:
Context在一次查询结束后,获得的数据会保存到本地缓存,在提交以前对数据的修改都是在本地进行。
当再次Qeury的时候,Context中不存在的数据会放到Context中,Context已经存在的数据(即便被修改了),也不会被数据库的数据覆盖。
Unit of Work模式指的是:
全部对于context中查询获得的实体对象的数据修改,都只会在调用SaveChanges方法后,才会真正的保存到数据库中。你能够在一个Context的生命周期中,修改多个实体对象的值,而后一次提交保存。
在EF中,因为Unit of Work模式,没有办法作选择性的保存数据,只要是数据发生了改动,都会在SaveChnage方法中一并提交到数据库中保存。
结合这两种模式,能够看出
在一个Context的生命周期中,一个Entity只会有一个实例,任何对该实例的修改,即便这些改动没有保存到数据库中,修改都会影响到整个Context的生命周期。
注意问题:
1. 在使用EF的时候,理想的方式应该是 获取数据-> 修改数据,保存数据->获取数据……的过程。
不要在修改数据的过程当中,再次请求数据,由于这些数据极可能和数据库中的数据不一致。
2. 在显示层,最好使用ViewModel, 而不要直接使用EF中Model.
好比一篇博客文章中,我只想显示前500个字给非注册用户看,若是使用Model, 不当心直接将文章内容的字段修改了,只保留了500个字,而后最后调用了SaveChange,用来保存文章的阅读次数。
这样就会致使文章内容被我不当心给丢失了。
下篇讨论如何在Asp.net MVC中实现One Context Per Request