• OA之框架的搭建


    1.使用框架可以有效的解决耦合性过高的问题,减少代码修改的程度,同时方便添加新的功能。首先创建出基本的几个类库。这个框架就是使用基本的逻辑分层三层架构,然后进一步再使用接口对每个逻辑中的类库调用进行解耦

    8个基本的类库:DAL、IDAL、DALFactory、Common、Model、BLL、IBLL、WebApp

    2.上层访问底层的时候,使用的是访问接口代替直接访问底层类,实现面向接口编程下面使用一个基本的表Users表搭建基本的框架。

    IDAL中因为有很多的公共的接口方法,比如说基本的增删改查,对于下面的每一个接口类(UserInfo、OrderInfo)中都存在这些接口,所以提出一个公共的接口IBaseDal<T>

    namespace OA.IDAL
    {
        //这是所有的dal中公有的方法
       public  interface IBaseDal<T> where T:class,new()
        {
            //获取满足条件的实体列表
            IQueryable<T> LoadEntity(System.Linq.Expressions.Expression<Func<T, bool>> whereLambda);
            //获取满足条件的分页数据列表(排序)
            IQueryable<T> LoadPageEntity<S>(int pageSize, int pageIndex, out int totalCount, System.Linq.Expressions.Expression<Func<T, bool>> whereLambda, System.Linq.Expressions.Expression<Func<T, S>> orderLambda, bool isAsc);
            //添加数据
            T AddEntity(T entity);
            //修改数据
            bool EditEntity(T entity);
            //删除数据
            bool DeleteEntity(T entity);
        }
    }

    对于参数T必须是一些Model中具体的类而不是接口,以为访问的接口中的方法就跟访问具体Dal中的方法是一样的,都是返回具体的查询的Model数据的。

    3.此时的IUserInfoDal只需要继承自IBaseDal<UserInfo>,然后在IUserInfo中只需要定义单独针对这张表的具体逻辑方法就好了。接口只是规范,规定无论是什么样的数据库,操作类都必须实现这些定义的接口规范(方法)

      public   interface IUserDal:IBaseDal<Users>
        {
           //定义自己特有的方法
        }

    4.接下来就是让UserDal实现IUserDal中的方法,也就是实现具体的增删改查这几个基本的方法,但是问题来了,出了返回的Model不同,其他的操作逻辑完全一致,所有,提出一个公共类BaseDal<T>,这个类的作用就是实现方法的共用,省去了在每一个子类中书写一遍这几个基本的方法。

    namespace OA.DAL
    {
        public   class BaseDal<T> where T:class,new()
        {
            Model.OAEntities dbContext = new Model.OAEntities();
            //记住添加引用EntityFarameWork
            public IQueryable<T> LoadEntity(System.Linq.Expressions.Expression<Func<T, bool>> whereLambda)
            {
                return dbContext.Set<T>().Where<T>(whereLambda);
            }
    
            public IQueryable<T> LoadPageEntity<S>(int pageSize, int pageIndex, out int totalCount, System.Linq.Expressions.Expression<Func<T, bool>> whereLambda, System.Linq.Expressions.Expression<Func<T, S>> orderLambda, bool isAsc)
            {
                //首先获取到totalCount
                IQueryable<T> totalEntities = dbContext.Set<T>().Where<T>(whereLambda);
                totalCount = totalEntities.Count();
                if (isAsc)
                {
                    totalEntities = totalEntities.OrderBy<T, S>(orderLambda).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
                }
                else
                {
                    totalEntities = totalEntities.OrderByDescending<T, S>(orderLambda).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
                }
                return totalEntities;
            }
    
            public T AddEntity(T entity)
            {
                dbContext.Entry<T>(entity).State = EntityState.Added;
                dbContext.SaveChanges();
                return entity;
            }
    
            public bool EditEntity(T entity)
            {
                dbContext.Entry<T>(entity).State = EntityState.Modified;
                return dbContext.SaveChanges() > 0;
            }
    
            public bool DeleteEntity(T entity )
            {
                dbContext.Entry<T>(entity ).State = EntityState.Deleted;
                return dbContext.SaveChanges() > 0;
            }
        }
    }

    上面的代码dbContext.Set<T>().Where<T>(whereLambda),这一句原来的代码是从dbContext.User.Where...修改过来的,因为不能使用DbContext.T.Where...,但是EntityFramework,使用Set<T>可以延迟获取到对应的内存表。同时上面的传递的参数都是Lambada表达式,因为对于数据的访问全部使用的是EntityFramework,它使用的就是Lambda表达式。

    5.将UserDal继承自BaseDal<Users>,然后在继承自IUsersDal,就可以了,同时一定先继承BaseDal然后再继承IUsersDal

    namespace OA.DAL
    {
        public  class UserDal:BaseDal<Users>,IUserDal
        {
           
        }
    }
    

     6.接下来在数据层和业务逻辑层添加一个数据访问层(DBSession),这个层封装了所有的数据访问层的Dal实例的创建,所以本质上来说,这个DBSession实际上就是一个工厂类,创建每一个实例,这种管理的方法实现了数据访问层图逻辑和业务逻辑城的解耦。它的主要的目的就是为了解决当操作多张表逻辑的时候,仅仅操作一次数据库,也就是实现工作单元模式。

    namespace OA.DALFactory
    {
        //其实就是相当于一个工厂类,用来创建Dal的实例,同时实现工作单元模式
      public   class DBSession
        {
          Model.OAEntities DbContext = new Model.OAEntities();
          //可以使用方法获取,也可以使用属性获取
          private IUserDal _userDal;
          public IUserDal UserDal 
          {
              get
              {
                  if (_userDal == null)
                  {
                      _userDal = new UserDal();
                  }
                  return _userDal;
              
              }
              set 
              {
                  _userDal = value;
              }
          }
          //实现工作单元模式
          public bool SaveChanges()
          {
              return DbContext.SaveChanges()>0;
          }
        }
    }

    7.工作单元模式已经实现了,那么在Dal中的所有的DBContext.SaveChanges()就需要去掉了

    namespace OA.DAL
    {
        public   class BaseDal<T> where T:class,new()
        {
            Model.OAEntities dbContext = new Model.OAEntities();
            //记住添加引用EntityFarameWork
            public IQueryable<T> LoadEntity(System.Linq.Expressions.Expression<Func<T, bool>> whereLambda)
            {
                return dbContext.Set<T>().Where<T>(whereLambda);
            }
    
            public IQueryable<T> LoadPageEntity<S>(int pageSize, int pageIndex, out int totalCount, System.Linq.Expressions.Expression<Func<T, bool>> whereLambda, System.Linq.Expressions.Expression<Func<T, S>> orderLambda, bool isAsc)
            {
                //首先获取到totalCount
                IQueryable<T> totalEntities = dbContext.Set<T>().Where<T>(whereLambda);
                totalCount = totalEntities.Count();
                if (isAsc)
                {
                    totalEntities = totalEntities.OrderBy<T, S>(orderLambda).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
                }
                else
                {
                    totalEntities = totalEntities.OrderByDescending<T, S>(orderLambda).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);
                }
                return totalEntities;
            }
    
            public T AddEntity(T entity)
            {
                dbContext.Entry<T>(entity).State = EntityState.Added;
                //dbContext.SaveChanges();
                return entity;
            }
    
            public bool EditEntity(T entity)
            {
                dbContext.Entry<T>(entity).State = EntityState.Modified;
              //  return dbContext.SaveChanges() > 0;
                return true;
            }
    
            public bool DeleteEntity(T entity )
            {
                dbContext.Entry<T>(entity ).State = EntityState.Deleted;
                //return dbContext.SaveChanges() > 0;
                return true;
            }
        }
    }

    8.那么此时出现了一个问题,我们在创建的UserDal(代码已经写在Basedal中了)已经创建过OAEntity的上下文对象了,此时在DBSession中有创建了一个,就是不一致了,因此需要解决一致性的问题。此时需要线程内唯一,

    既然在DBSession中需要new一个对象,在BaseDal中也是需要new一个对象,实际上就是一个工厂类,与其在每一各类中都写一遍保证线程内唯一的判断,不如直接使用工厂

     1 namespace OA.DAL
     2 {
     3     public static   class DBContextFactory
     4     {
     5         //工厂类的作用就是创建实例对象,可以包括相同的实例,也可以是不相同的实例,同时使用CallContext(这个对象跟HttpContext作用是一样的)实现线程内唯一对象
     6         
     7         public Model.OAEntities CreateDBContext()
     8         {
     9             Model.OAEntities dbContext = (Model.OAEntities)CallContext.GetData("dbContext");
    10             if (dbContext == null)
    11             {
    12                 dbContext = new Model.OAEntities();
    13                 CallContext.SetData("dbContext", dbContext);
    14             }
    15             return dbContext;
    16         }
    17     }
    18 }

    这个工厂比较特殊,因为他是生产的是同一个对象,它可以随便找个类库存放,但是不能存放在DalFactory中,因为DalFactory中引用了DAL和IDAL这两个类库,如果写在DALFactory中,BaseDal需要使用dbContext,需要引用DAlFactory,存在相互引用的错误,所以直接把DBContextFactory,直接放在DAL下面

    9.修改BaseDal和DBSession中对EF对象的获取方式,保证线程内的唯一

    BaseDal修改: 
     public   class BaseDal<T> where T:class,new()
        {
            DbContext dbContext = DBContextFactory.CreateDBContext();
        。。。。。。。。。。
       }
    
    DBSession修改:
     public   class DBSession
        {
           public DbContext dbContext { 
              get { return DBContextFactory.CreateDBContext(); } 
          }
       。。。。。。。
       }

    10.对于DBSession中需要获取到具体的Dal操作类的实例,但是全部使用new的方式创建的,造成耦合性太高,此时需要创建抽象工厂类,使用反射的机制创建具体的实力类,以后修改仅仅需要修改配置就好了。

    namespace OA.DALFactory
    {
      public   class AbstractFactory
        {
          public static readonly string AssemblyPath = ConfigurationManager.AppSettings["AssemblyPath"].ToString();
          public static readonly string NameSpace = ConfigurationManager.AppSettings["NameSpace"].ToString();
          public static IUserDal CerateUserDal()
          {
              string fullClassName = AssemblyPath + ".UserDal";
             return  CreateInstance(fullClassName ) as IUserDal ;
          }
          private static  object CreateInstance(string fullClassName)
          {
              Assembly assmbly = Assembly.Load(AssemblyPath);
              return   assmbly.CreateInstance(fullClassName);
          }
        }
    }

    11.BLL层对DBSession访问,应该访问相应的接口,实现解耦合

    namespace OA.IDAL
    {
      public   class IDBSession
        {
          DbContext DbContext
          {
              get;
          }
          IUserDal UserDal{get;set;}
          bool SaveChanges();
        }
    }

    然后让DBSession实现IDBSession的接口

    12.接下来是对业务层的搭建,同时存在很多的通用的代码,比如增删改查,同时需要创建出DBSession的实例,每一个子类中都需要创建一个DBSession ,所以在父类中创建。

    namespace OA.BLL
    {
        public abstract  class BaseService<T>
        {
            public IDBSession CurrentDBSession { get { return new DBSession(); } }//在子类中也使用
            public IBaseDal<T> CurrentDal { get; set; }
            public abstract void SetCurrentDal();
            public BaseService()
            {
                SetCurrentDal();
            }
            IQueryable<T> LoadEntity(System.Linq.Expressions.Expression<Func<T, bool>> whereLambda)
            {
               //return   CurrentDBSession.UserDal.LoadEntity(whereLambda);并不确定T是什么
                return CurrentDal.LoadEntity(whereLambda);
            }
            public IQueryable<T> LoadPageEntity<S>(int pageSize, int pageIndex, out int totalCount, System.Linq.Expressions.Expression<Func<T, bool>> whereLambda, System.Linq.Expressions.Expression<Func<T, S>> orderLambda, bool isAsc)
            {
              return   CurrentDal.LoadPageEntity<S>(pageSize, pageIndex, out totalCount, whereLambda, orderLambda, isAsc);
            }
            public T AddEntity(T entity)
            {
                CurrentDal.AddEntity(entity);
                CurrentDBSession.SaveChanges();
                return entity;
    
            }
            public bool EditEntity(T entity)
            {
                CurrentDal.EditEntity(entity);
                return  CurrentDBSession.SaveChanges();
               
            }
            public bool DeleteEntity(T entity)
            {
                CurrentDal.DeleteEntity(entity);
               return  CurrentDBSession.SaveChanges();
            }
        }
    }

    13.让具体业务子类继承BaseService

    namespace OA.BLL
    {
       public  class UserService:BaseService<Users>
        {
    
            public override void SetCurrentDal()
            {
                //在具体的业务子类中可以确定确定具体的是哪一个Dal
                CurrentDal = CurrentDBSession.UserDal;
            }
        }
    }

    14.封装业务类的接口,对于每一个业务类中的接口,增删改查除了返回的类型不同,方法完全相同,为了避免重复,提取父类IBaseServie<T

    namespace OA.IBLL
    {
       public  interface IBaseService<T>
        {
           IDBSession CurrentDBSession { get; }
           IBaseDal<T> CurrentDal { get; set; }
           IQueryable<T> LoadEntity(System.Linq.Expressions.Expression<Func<T, bool>> whereLambda);
           IQueryable<T> LoadPageEntity<S>(int pageSize, int pageIndex, out int totalCount, System.Linq.Expressions.Expression<Func<T, bool>> whereLambda, System.Linq.Expressions.Expression<Func<T, S>> orderLambda, bool isAsc);
           T AddEntity(T entity);
           bool EditEntity(T entity);
           bool DeleteEntity(T entity);
        }
    }

    15.创建具体的每一个业务子类的接口,以IUserService为例。

    namespace OA.IBLL
    {
       public  interface IUserService:IBaseService<Model.Users>
        {
        }
    }

    16.创建具体的业务子类,以UserService为例

     1 namespace OA.BLL
     2 {
     3    public  class UserService:BaseService<Users>,IUserService
     4     {
     5        //并不会手动去调用这个方法,所以没必要写在接口里
     6         public override void SetCurrentDal()
     7         {
     8             //在具体的业务子类中可以确定确定具体的是哪一个Dal
     9             CurrentDal = CurrentDBSession.UserDal;
    10         }
    11     }
    12 }

    17.由于BaseService中虽然简化了创建DBSession的代码,但是逻辑上依然没有减少,每次都new(),然而对于同一个逻辑操作多次数据库,此时需要多次CurrentSession,每次调用都有new,此时逻辑有点问题,同时创建了多个,因为不是同一个CurrentSession

    namespace OA.DALFactory
    {
        public   class DBSessionFactory
        {
            public static  IDBSession CreateDbSession()
            {
                IDBSession dbSession =(IDBSession) CallContext.GetData("dbSession");
                if (dbSession == null)
                {
                    dbSession = new DBSession();
                    CallContext.SetData("dbSession", dbSession);
                }
                return dbSession;
            }
        }
    }
    
    同时将BaseService中获取DBSession方式
    改为
     public abstract  class BaseService<T> where T:class,new()
        {
           // public IDBSession CurrentDBSession { get { return new DBSession(); } }//在子类中也使用
            public IDBSession CurrentDBSession { get { return  DBSessionFactory.CreateDbSession(); } }//在子类中也使用
    
    。。。。。。
         }

    18.UI层就可以直接使用

    IUserService user=new UserService();直接使用,没有必要再单独创建工厂,因为一般不会随意改动UI层和BLL层

    搭建完毕。

  • 相关阅读:
    使用用Ghost制作的win2k3和winxp文件具有相同的SID的解决办法
    64 bits Windows 7 使用 regsvr32 的註冊方式(转)
    怎么实现用户匿名访问web,但数据库要用Windows集成验证方式(数据库和web服务器分别在两台机器上)
    为什么按照微软给定的匿名配置Web 同步最终造成创建订阅的步骤总是失败?但改为需要身份验证就行了
    How to edit Team Build Types
    利用WhiteHose一步步建立分布式系统的框架(二)创建LDD步骤
    发现:InfoPath 2007 Training Labs地址
    在MSF中怎么区分易混淆的工作项类型:Bug、风险和问题(我个人的理解)
    RGB Colour Map
    How to distinguish Design time or Running time in Mobile cusotmer Contorl(the NetCF2.0 is different to NetCF1.0)
  • 原文地址:https://www.cnblogs.com/XZhao/p/6685724.html
Copyright © 2020-2023  润新知