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层

搭建完毕。

posted @ 2017-04-09 18:07  善良的小赵  阅读(2481)  评论(0编辑  收藏  举报