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 - ) * pageSize).Take<T>(pageSize);
}
else
{
totalEntities = totalEntities.OrderByDescending<T, S>(orderLambda).Skip<T>((pageIndex - ) * 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() > ;
} public bool DeleteEntity(T entity )
{
dbContext.Entry<T>(entity ).State = EntityState.Deleted;
return dbContext.SaveChanges() > ;
}
}
}

上面的代码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()>;
}
}
}

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 - ) * pageSize).Take<T>(pageSize);
}
else
{
totalEntities = totalEntities.OrderByDescending<T, S>(orderLambda).Skip<T>((pageIndex - ) * 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一个对象,实际上就是一个工厂类,与其在每一各类中都写一遍保证线程内唯一的判断,不如直接使用工厂

 namespace OA.DAL
{
public static class DBContextFactory
{
//工厂类的作用就是创建实例对象,可以包括相同的实例,也可以是不相同的实例,同时使用CallContext(这个对象跟HttpContext作用是一样的)实现线程内唯一对象 public Model.OAEntities CreateDBContext()
{
Model.OAEntities dbContext = (Model.OAEntities)CallContext.GetData("dbContext");
if (dbContext == null)
{
dbContext = new Model.OAEntities();
CallContext.SetData("dbContext", dbContext);
}
return dbContext;
}
}
}

这个工厂比较特殊,因为他是生产的是同一个对象,它可以随便找个类库存放,但是不能存放在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为例

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

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层

搭建完毕。

OA之框架的搭建的更多相关文章

  1. 基于C/S架构的3D对战网络游戏C++框架 _06搭建C/S架构的基本通信框架(尚未写完会重新编辑后再发出)

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  2. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  3. Spring+SpringMvc+Mybatis框架集成搭建教程

    一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...

  4. eclipse中SSH三大框架环境搭建<三>

    相关链接: eclipse中SSH三大框架环境搭建<一> eclipse中SSH三大框架环境搭建<二> 引言:通过上两篇文章我们已经可以掌握struts2和spring的环境的 ...

  5. eclipse中SSH三大框架环境搭建<二>

    通过上一篇博客我们可以轻松搭建strtus2的环境,接下来由我来继续介绍spring的环境搭建以及spring注入的简单使用 相关链接:eclipse中SSH三大k框架环境搭建<一> ec ...

  6. Struts2+Spring+Hibernate(SSH)框架的搭建

    首先需要下载struts2 ,spring4,hibernate5  的资源包; struts2资源包下载路径:http://www.apache.org/spring资源包下载路径:http://p ...

  7. Ext.NET 4.1 系统框架的搭建(后台) 附源码

    Ext.NET 4.1 系统框架的搭建(后台) 附源码 代码运行环境:.net 4.5  VS2013 (代码可直接编译运行) 预览图: 分析图: 上面系统的构建包括三块区域:North.West和C ...

  8. eclipse中SSH三大框架环境搭建<一>

    这里先简单介绍一下我用的三大框架版本以及下载地址 相关链接:eclipse中SSH三大框架环境搭建<二> eclipse中SSH三大框架环境搭建<三> struts-2.3.3 ...

  9. iOS基础框架的搭建/国际化操作

    1.基础框架的搭建 1.1 pod引入常用的第三方类库 1.2 创建基础文件夹结构/目录结构 Resource———存放声音/图片/xib/storyboard 等资源文件 Define——宏定义, ...

  10. iOS之UI--主流框架的搭建--仿制QQ的UI框架

    使用XCode搭建多个控制器界面,一般在实际开发中建议超过四个控制器界面使用纯代码. 下面的实例其实已经超过了四个,总结详细步骤的目的,主要是更熟悉XCode的StoryBoard使用细节. 先直接上 ...

随机推荐

  1. javascript删除字符串最后一个字符

    搜到很多无用的答案,这对新手来讲是很耗费时间的事情,我把正确的方法贴出来,以便有的新手不再踩这个坑. JavaScript slice() 方法 定义和用法 slice() 方法可提取字符串的某个部分 ...

  2. 【问题】报错[CRITICAL] Rendering SLS 'base:minions.install' failed: Jinja variable 'list' object has no element 0

    1.报错[CRITICAL] Rendering SLS 'base:minions.install' failed: Jinja variable 'list' object has no elem ...

  3. Windows性能监视器

    前端时间在做动态目标监控,应用程序需要考虑大数据量和多用户并发的操作,系统的性能是解决方案实施性的重要度量.这里简单的记录下Windows中性能监视查看和简单分析. 一般操作系统性能主要涉及到的问题主 ...

  4. MathType有哪些功能

    随着寒流呼呼来临,期末考也不放过我们,不知道你们是在题海里遨游,还是已做好了挑战准备呢.不管你是哪种情况,现在就有一款玩转理工科的强大编辑公式强悍来袭,不管你是学生.教师,还是理科专业工作者,Math ...

  5. libui-node体验笔记

    简介 libui-node是基于libui库的node封装.libui库是一个简便的将本地原生的GUI封装的C语言库,并支持各平台(Mac,Linux,windows).官网提供了第三方封装文档,开发 ...

  6. 关于java之socket输入流输出流可否放在不同的线程里进行处理

    2014年2月20日到叫(黑土)(人士)的公司去面试,一家新成立的公司.刚去公司是他们新聘请的猎头A来面试我的,A面试完之后是一个号称X总的年轻人来面试我,初一见此人有点邋遢,穿着西装. X:&quo ...

  7. C#获取CPU处理器核心数量的方法_C#教程

    https://yq.aliyun.com/ziliao/89096 摘要: 本文讲的是C#获取CPU处理器核心数量的方法_C#教程, 有几条不同的处理器信息,您可以获得有关的信息:物理处理器数量.核 ...

  8. 工作流JBPM_day01:2-HelloWorld

    工作流JBPM_day01:2-HelloWorld 新建一个java工程Jbpm4.4 拷贝helloworld.jpdl.xml和helloworld.png文件出来压缩成helloworld.z ...

  9. Effective C++ Item 16 Use the same form in corresponding uses of new and delete

    1. When you created an array and want to return the memory to system. You need to explicitly add [] ...

  10. Nginx(二)-- 配置文件之虚拟主机配置

    1.配置文件与解释 #user nobody; worker_processes 1; # 设置工作子进程,默认是1个工作子进程,可以修改,一般设置为CPU的总核数 #error_log logs/e ...