zoukankan      html  css  js  c++  java
  • EF的性能改善和思考

    EF是个工具,用的好了性能就会很好,用的不好性能就会有很大损失。

    先从EF的设计思想来讲解

    EF的初衷是根据缓存中的实体对象,以及实体对象的状态(删除、更新、添加)来对数据库进行操作,这些实体对象、以及对象的状态都是在一个对象上下文ObjectContext中进行维护的,数据上下文DbContext显式实现了IObjectContextAdapter接口。DbContext在最后SaveChanges提交的时候,会调用ObjectContext的SaveChanges, 将所有更新保存到数据库并重置对象上下文中的更改跟踪。所以DbContext是对ObjectContext进行的二次封装和完善。

    1.EF的初衷是好的,避免对数据库频繁的提交,先操作实体对象,直到实体对象不需要再更改了,最后提交的时候再将所有更新保存到数据库。但是凡事都是相对的,如果维护了大量的实体会使内存消耗很大,所以怎么办呢,应该尽量避免不必要的缓存实体,譬如纯粹的查询,EF在查询的时候可以使用AsNoTracking()避免将查询的实体或者实体序列放在缓存中,这在很大程度可以节省了内存。

    2.EF鼓励将多个操作放在一个数据上下文中,所以有人说采用EF不需要DAL层了,可以直接在业务层包装using(DbContext=new DbContext()){},然后对数据库做各种表的操作,这个是没问题的,但是在开发中,这样做效率会很低,会写很多重复代码,举个简单的例子,假如一个条件查询,如果有DAL层的封装方法,我就可以在业务层方便的调用,避免每次都去想着怎么去组装条件进行查询,所以DAL层对于开发效率来说还是必要的,如果需要DAL层就要考虑数据仓储类的实现,数据仓储类该如何实现呢?

    3.数据仓储类,数据仓储类封装了通用的针对数据库的单元操作方法,封装这些方法中应该避免使用using(DbContext=new DbContext()){}包装单元操作,EF的设计初衷是什么?避免频繁的与数据库进行交互,如果采用这种方式封装单元操作,一个单元操作使用一个数据上下文,那么EF的性能优势在哪里?另外采用这种方式封装,EF的“本地事务”也被破坏了,已经毫无”事务”可言,所以数据仓储类可以采用一个临时公用的数据上下文,比如你将数据上下文放在线程对象中,这里的事务我加了一个引号,因为EF在提交的时候根据对象上下文来更新数据库的,所以最后一次提交之前,实际上并没有和数据库交互,数据上下文提交的时候,会进行事务的封装,如果失败了,本次提交的所有操作回滚。

    4.EF的初衷是想维护一个完整性的对象上下文,但是实际生产中很难做到,比如执行了一个sqlcommand更新了一个字段,但是对象上下文中的该属性没有被更新,所以也许会说,采用EF就避免使用sql进行操作了,但是Dbcontext留下了DataBase口子,public int ExecuteSqlCommand(string sql, params object[] parameters);留下了口子,就避免不了会被采用,所以更稳妥的做法是采用DbContextTransaction来控制事务,而不是单纯地依靠SaveChanges,另外如果采用了ExecuteSqlCommand,一旦破坏了数据对象的完整性,再进行更新操作的时候很可能会覆盖掉之前执行的操作,那么怎么办呢,解决办法有两个,1.根据字段进行更新,而不是更新整个实体2.将数据对象分离,重新附加,然后更新,很明显1的方法性能更好

    5.如何Dispose掉Dbcontext?首先要清楚Dispose是干什么的,Dispose是为了释放资源,不是销毁对象,销毁对象是谁干的,销毁对象是GC干的,GC准备销毁对象的时候,会检查对象有么有析构函数,如果有会将这些对象升级暂不销毁,直到全部执行完析构,在下次回收的时候再销毁掉,可是Dbcontext没有析构函数,但是Dbcontext是对ObjectContext的二次封装和完善,ObjectContext实现了析构,所以如果Dbcontext没有显示的去Dispose,GC回收数据上下文对象的时候,会升级该对象,直到所有的析构执行完毕,在下次回收的时候再一并销毁掉。我们不知道垃圾回收的具体时间,但是显示的Dispose可以减少Dbcontext对象的生命周期。所以在应用程序中,我们可以在请求结束的最后,执行显示的Dispose,譬如对于mvc、webapi程序,可以在过滤器中,请求结束的时候执行Dispose操作,对于asp.net可以在basepage中进行Dispose操作。

     //
        // 摘要:
        //     由可提供 System.Data.Entity.Infrastructure.IObjectContextAdapter.ObjectContext 实例的对象实现的接口。System.Data.Entity.DbContext
        //     类实现此接口以提供对基础 ObjectContext 的访问。
        public interface IObjectContextAdapter
        {
            //
            // 摘要:
            //     获取对象上下文。
            //
            // 返回结果:
            //     对象上下文。
            ObjectContext ObjectContext { get; }
        }
     //
        // 摘要:
        //     DbContext 实例表示工作单元和存储库模式的组合,可用来查询数据库并将更改组合在一起,这些更改稍后将作为一个单元写回存储区中。DbContext 在概念上与
        //     ObjectContext 类似。
        public class DbContext : IDisposable, IObjectContextAdapter
        {
            //
            // 摘要:
            //     将在此上下文中所做的所有更改保存到基础数据库。
            //
            // 返回结果:
            //     已写入基础数据库的对象的数目。
            public virtual int SaveChanges();
  • 相关阅读:
    Django入门
    外星人入侵完整版
    外星人入侵
    简单的socket通信
    购物车程序
    列表的使用&元组
    三目运算的使用&bytes类型转str类型
    hdu 2586 How far away ?
    hdu 1075 What Are You Talking About
    洛谷 P2292 [HNOI2004]L语言
  • 原文地址:https://www.cnblogs.com/njcxwz/p/6257189.html
Copyright © 2011-2022 走看看