Entity Framework中的Identity map和Unit of Work模式

阅读目录:数据库

1、什么是Identity map模式缓存

2、关于Identity map模式的验证示例ide

3、Unit of Work 模式spa

4、总结和注意的问题.net

一,什么是Identity map模式

Identity map是EF获取和缓存数据的模式。
Identity map模式指的是任何数据都只会被加载一次,以map的形式缓存,以惟一的identity来再次获取这些数据。
在EF中,就是在一个Context的生命周期中,全部查询过的数据都会缓存到Context的local中缓存。当再次访问这些数据的时候,就会以主键(identity)从缓存中获取这些数据。3d

二,关于Identity map模式的验证示例

看看下面这段代码运行的结果: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.生命周期

image

 

image

可是根据MiniProfiler的监控结果,EF的确访问了2次数据库

image

 

从这里,得出的结论是:

Context在一次查询结束后,获得的数据会保存到本地缓存,在提交以前对数据的修改都是在本地进行。
当再次Qeury的时候,Context中不存在的数据会放到Context中,Context已经存在的数据(即便被修改了),也不会被数据库的数据覆盖。

三. Unit of Work 模式

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

相关文章
相关标签/搜索