1、了解EF的三种数据加载模式
a)Lazy Loading
i.默认ef是使用此模式,显示开启在DbContext的构造器中使用Configuration.LazyLoadingEnabled=true;
ii.此模式中(codefirst),领域模型不能被声明为sealed,导航属性必须声明为virtual。因为框架会自动为模型生成一个代理类,在访问导航属性时代理类重写导航属性,从数据源读取数据并返回实体或集合。
iii.在对应到遍历实体的时候再遍历对应导航属性,此时需要开启sqlserver的mars选项,可直接在连接字串中配置。
iv.Lazy Loading模式只有在访问对应实体的导航属性时才会加载该数据。
b)Eager Loading
i.开启ef的Eager Loading模式需要在DbContext的构造其中使用Configuration.LazyLoadingEnabled=false;或者(codefirst)将领域模型声明为sealed,导航属性声明为非virtual,这样都可以导致Lazy Loading的失效。
ii.在Eager Loading模式下,加载导航属性的值需要显示调用Include方法,传入导航属性属性名的字符串。或者引入System.Data.Entity命名空间,使用Include的强类型方法。
iii.Eager Loading模式将主数据和导航属性数据一次性全部加载进内存。
c)Explicit Loading
i.Explicit Loading和Lazy Loading相似。导航属性的数据都是在主数据加载完后加载的,不同的是Lazy Loading会在访问导航属性时自动加载数据而Explicit Loading需要在访问导航属性数据前手动调用DbContext.Entry(T).Collection(x=>x.NavigationProperty).Load();[访问实体集合]或DbContext.Entry(T).Reference(x=>x.NavigationProperty).Load();[访问实体]此时数据被加载到内存中,然后访问导航属性即可。以上Load()方法返回的是void类型。如果将Load()替换为Query(),Query()方法返回的是IQueryAble<T>类型,所以可直接在返回结果上进行读取或遍历操作。
ii.Explicit Loading模式下允许领域模型的导航属性声明为非virtual,但是导航属性声明为virtual且未置LazyLoadingEnabled为false会自动启用Lazy Loading模式。
iii.Explicit Loading模式需要手动控制在什么时候加载数据。
2、在已知实体标识的情况下使用Find方法查找,该方法会先在EF的对象管理缓存查找,如果没有再在数据源中查找。这在某些情况下比直接调用Single或First等高效。若查不到数据,该方法返回null。
3、在更改导航属性上的对象时,先将对象加载到EF的上下文中,EF可以知道该对象的状态是新添加的还是修改或已删除的,然后再应用到实体的导航属性上。比如直接在实体导航属性上添加一个对象和先将新建对象放入EF的上下文中再关联到实体的导航属性上,EF在SaveChanges时就不需要插叙数据库来判断这个新加的对象是否已存在,以减少生成的sql语句。
4、在以下操作中会触发DetectChanges方法的调用。
a) DbSet.Add DbSet.Find DbSet.Remove DbSet.Local DbContext.SaveChanges
b) 任何对DbSet执行的Linq查询
c) DbSet.Attach DbContext.GetValidationErrors DbContext.Entry DbChangeTracker.Entries
触发DetectChanges方法在性能要求苛刻的环境下是需要避免的,通过将DbContext.Configuration.AutoDetectChangesEnabled置为false可以阻止EF自动调用DetectChanges方法。如果我们进行了一系列的API调用却不改变任何对象,可以避免一些不必要的执行DetectChanges的过程。例如再大量数据插入的时候。
5、在获取数据时,如果只将数据作为展示,而不需要进行状态跟踪修改,使用AsNoTracking()方法将会有明显的性能提升。使用AsNoTracking()方法需要引入System.Data.Entity命名空间。