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 - ) * 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之框架的搭建的更多相关文章
- 基于C/S架构的3D对战网络游戏C++框架_06搭建C/S架构的基本通信框架(尚未写完会重新编辑后再发出)
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- Spring+SpringMvc+Mybatis框架集成搭建教程
一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...
- eclipse中SSH三大框架环境搭建<三>
相关链接: eclipse中SSH三大框架环境搭建<一> eclipse中SSH三大框架环境搭建<二> 引言:通过上两篇文章我们已经可以掌握struts2和spring的环境的 ...
- eclipse中SSH三大框架环境搭建<二>
通过上一篇博客我们可以轻松搭建strtus2的环境,接下来由我来继续介绍spring的环境搭建以及spring注入的简单使用 相关链接:eclipse中SSH三大k框架环境搭建<一> ec ...
- Struts2+Spring+Hibernate(SSH)框架的搭建
首先需要下载struts2 ,spring4,hibernate5 的资源包; struts2资源包下载路径:http://www.apache.org/spring资源包下载路径:http://p ...
- Ext.NET 4.1 系统框架的搭建(后台) 附源码
Ext.NET 4.1 系统框架的搭建(后台) 附源码 代码运行环境:.net 4.5 VS2013 (代码可直接编译运行) 预览图: 分析图: 上面系统的构建包括三块区域:North.West和C ...
- eclipse中SSH三大框架环境搭建<一>
这里先简单介绍一下我用的三大框架版本以及下载地址 相关链接:eclipse中SSH三大框架环境搭建<二> eclipse中SSH三大框架环境搭建<三> struts-2.3.3 ...
- iOS基础框架的搭建/国际化操作
1.基础框架的搭建 1.1 pod引入常用的第三方类库 1.2 创建基础文件夹结构/目录结构 Resource———存放声音/图片/xib/storyboard 等资源文件 Define——宏定义, ...
- iOS之UI--主流框架的搭建--仿制QQ的UI框架
使用XCode搭建多个控制器界面,一般在实际开发中建议超过四个控制器界面使用纯代码. 下面的实例其实已经超过了四个,总结详细步骤的目的,主要是更熟悉XCode的StoryBoard使用细节. 先直接上 ...
随机推荐
- 【转】WCF入门教程二[WCF应用的通信过程]
一.概述 WCF能够建立一个跨平台的安全.可信赖.事务性的解决方案,是一个WebService,.Net Remoting,Enterprise Service,WSE,MSMQ的并集,有一副很经典的 ...
- 正则表达式”\d+\.?\d*”在匹配下列字符串时结果是失败的是?
A 12.5 B 1.25 C 以上都成功 D 以上都失败 解答:B \d+ 表示可以出现1次或是n次数字 \. .? 表示可以“.”可以出现一次,也可以不出现 \d* 表示可以出现0次或是n次数字
- 如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有事务。命令的 Transaction 属性尚未初始化
DbConnection dbc = database.CreateConnection(); DbTransaction dbtt = null; try { dbc.Open(); dbtt = ...
- bt开源的客户端——xbt client
我部署好了bt tracker, 用bitcomet可以下载. 但xbt client下载不来.torrent资源.
- js省市二级联动
html: <script src="js/city.js"></script> ...... <body> <div class=&qu ...
- 关于MFC中的OnPaint和OnDraw
当窗口发生改变后,会产生无效区域,这个无效的区域需要重画. 一般Windows会发送两个消息WM_PAINT(通知客户区 有变化)和WM_NCPAINT(通知非客户区有变化). 非客户区的重画系统自己 ...
- codeforces 547A Mike and Frog
近期都是这样的题呢. . .... 哎 開始想纯暴力(体如今跳出循环t>=那里.,,,)..,.随着数据变大.. ...(t=499981500166是能够的),,,..,,23333333 超 ...
- 自定向下分析Binder 之 Binder Model(1)
Java层的Binder对象模型: IBinder IBinder是Binder通信机制中的核心部分(Base interface for a remotable object, the core p ...
- java中Date的使用情况
在开发中常使用情况. 1.将String转为date 例如"201604131630" //设置日期格式 public SimpleDateFormat sdf = new Si ...
- kafka中配置细节
今天遇到kafka发送消息的时候,一直报Kafka“Failed to send messages after 3 tries”错误,根据网上找问题,修改各种配置参数,各种重启,还是解决不了问题. 郁 ...