EF--封装三层架构IOC
- 为什么分层?
不分层封装的话,下面的代码就是上端直接依赖于下端,也就是ui层直接依赖于数据访问层,分层一定要依赖抽象,满足依赖倒置原则,所以我们要封装,要分层
下面这张图和传统的三层略有不同,不同之处在于,ui层不直接依赖于业务逻辑层,而是ui层依赖于业务逻辑抽象层ibll,业务逻辑层不直接依赖于数据访问层,而是业务逻辑层依赖于数据访问抽象层idal
{ schooldbentities dbcontext = new schooldbentities(); dbcontext.set<student>().where(s=>s.student_id == "0000000001"); }
- 封装分层
1、david.general.ef.bussiness.interface(ibll--业务逻辑抽象层)
继承idisposable的目的是为了可以使用using,是为了释放context
ibaseservice相当于上图的ibll(业务逻辑抽象层),dal已经不存在了,因为ef已经取代了dal层
namespace david.general.ef.bussiness.interface { public interface ibaseservice : idisposable//可以使用using,是为了释放context { #region query /// <summary> /// 根据id主键查询实体 /// </summary> /// <param name="id"></param> /// <returns></returns> t find<t>(object id) where t : class; /// <summary> /// 提供对单表的查询 /// 不推荐对外直接开放 ///iqueryable支持表达式目录树 /// </summary> /// <returns>iqueryable类型集合</returns> [obsolete("尽量避免使用,using 带表达式目录树的 代替")] iqueryable<t> set<t>() where t : class; /// <summary> /// 查询,传入表达式目录树 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="funcwhere">表达式目录树</param> /// <returns>iqueryable类型集合</returns> iqueryable<t> query<t>(expression<func<t, bool>> funcwhere) where t : class; /// <summary> /// 分页查询 /// </summary> /// <typeparam name="t"></typeparam> /// <typeparam name="s"></typeparam> /// <param name="funcwhere"></param> /// <param name="pagesize"></param> /// <param name="pageindex"></param> /// <param name="funcorderby"></param> /// <param name="isasc"></param> /// <returns></returns> pageresult<t> querypage<t, s>(expression<func<t, bool>> funcwhere, int pagesize, int pageindex, expression<func<t, s>> funcorderby, bool isasc = true) where t : class; #endregion #region add /// <summary> /// 新增数据 /// </summary> /// <param name="t"></param> /// <returns>返回带主键的实体</returns> t insert<t>(t t) where t : class; /// <summary> /// 新增数据 /// 多条sql 一个连接,事务插入 /// </summary> /// <param name="tlist"></param> ienumerable<t> insert<t>(ienumerable<t> tlist) where t : class; #endregion #region update /// <summary> /// 更新数据 /// </summary> /// <param name="t"></param> void update<t>(t t) where t : class; /// <summary> /// 更新数据 /// </summary> /// <param name="tlist"></param> void update<t>(ienumerable<t> tlist) where t : class; #endregion #region delete /// <summary> /// 根据主键删除数据 /// </summary> /// <param name="t"></param> void delete<t>(int id) where t : class; /// <su+mary> /// 删除数据 /// </summary> /// <param name="t"></param> void delete<t>(t t) where t : class; /// <summary> /// 删除数据 /// </summary> /// <param name="tlist"></param> void delete<t>(ienumerable<t> tlist) where t : class; #endregion #region other /// <summary> /// 立即保存全部修改 /// 把增/删的savechange给放到这里,是为了保证事务的 /// </summary> void commit(); /// <summary> /// 执行sql 返回集合 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> iqueryable<t> excutequery<t>(string sql, sqlparameter[] parameters) where t : class; /// <summary> /// 执行sql,无返回 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> void excute<t>(string sql, sqlparameter[] parameters) where t : class; #endregion } } public class pageresult<t> { public int totalcount { get; set; } public int pageindex { get; set; } public int pagesize { get; set; } public list<t> datalist { get; set; } }
2、david.general.ef.bussiness.service(业务逻辑实现层)
namespace david.general.ef.bussiness.service { public class baseservice : ibaseservice { #region identity /// <summary> /// protected--保证只有子类可以看得见 /// { get; private set; }--保证只有子类可以获取,子类不能修改,只有自己可以修改 /// </summary> protected dbcontext context { get; private set; } /// <summary> /// 构造函数注入 /// 一个请求一个,不能全局一个,应该一个实例一个 /// </summary> /// <param name="context"></param> public baseservice(dbcontext context) { this.context = context; } #endregion identity #region query /// <summary> /// 通过id得到实体 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="id"></param> /// <returns></returns> public t find<t>(object id) where t : class { return this.context.set<t>().find(id); } /// <summary> /// 不应该暴露给上端使用者,尽量少用 /// </summary> /// <typeparam name="t"></typeparam> /// <returns></returns> [obsolete("尽量避免使用,using 带表达式目录树的代替")] public iqueryable<t> set<t>() where t : class { return this.context.set<t>(); } /// <summary> /// 这才是合理的做法,上端给条件,这里查询 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="funcwhere"></param> /// <returns></returns> public iqueryable<t> query<t>(expression<func<t, bool>> funcwhere) where t : class { return this.context.set<t>().where<t>(funcwhere); } /// <summary> /// 分页查询 /// </summary> /// <typeparam name="t"></typeparam> /// <typeparam name="s"></typeparam> /// <param name="funcwhere">查询条件表达式目录树</param> /// <param name="pagesize">页大小</param> /// <param name="pageindex">页索引</param> /// <param name="funcorderby">按什么字段排序</param> /// <param name="isasc">升序还是降序</param> /// <returns></returns> public pageresult<t> querypage<t, s>(expression<func<t, bool>> funcwhere, int pagesize, int pageindex, expression<func<t, s>> funcorderby, bool isasc = true) where t : class { var list = this.set<t>(); if (funcwhere != null) { list = list.where<t>(funcwhere); } if (isasc) { list = list.orderby(funcorderby); } else { list = list.orderbydescending(funcorderby); } pageresult<t> result = new pageresult<t>() { datalist = list.skip((pageindex - 1) * pagesize).take(pagesize).tolist(), pageindex = pageindex, pagesize = pagesize, totalcount = this.context.set<t>().count(funcwhere) }; return result; } #endregion #region insert /// <summary> /// 插入 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="t"></param> /// <returns></returns> public t insert<t>(t t) where t : class { this.context.set<t>().add(t); return t; } /// <summary> /// 插入集合 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="tlist"></param> /// <returns></returns> public ienumerable<t> insert<t>(ienumerable<t> tlist) where t : class { this.context.set<t>().addrange(tlist); return tlist; } #endregion #region update /// <summary> /// 是没有实现查询,直接更新的,需要attach和state /// /// 如果是已经在context,只能再封装一个(在具体的service) /// </summary> /// <typeparam name="t"></typeparam> /// <param name="t"></param> public void update<t>(t t) where t : class { if (t == null) throw new exception("t is null"); this.context.set<t>().attach(t);//将数据附加到上下文,支持实体修改和新实体,重置为unchanged this.context.entry<t>(t).state = entitystate.modified;//全字段更新 } /// <summary> /// 集合修改 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="tlist"></param> public void update<t>(ienumerable<t> tlist) where t : class { foreach (var t in tlist) { this.context.set<t>().attach(t); this.context.entry<t>(t).state = entitystate.modified; } } /// <summary> /// 更新数据,指定更新哪些列,哪怕有些列值发生了变化,没有指定列也不能修改 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="t"></param> public void updatespecifyfiled<t>(t t, list<string> filedlist) where t : class { this.context.set<t>().attach(t);//将数据附加到上下文 foreach(var filed in filedlist) { this.context.entry<t>(t).property(filed).ismodified = true;//指定某字段被改过 } } #endregion #region delete /// <summary> /// 先附加 再删除 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="t"></param> public void delete<t>(t t) where t : class { if (t == null) throw new exception("t is null"); this.context.set<t>().attach(t); this.context.set<t>().remove(t); } /// <summary> /// 还可以增加非即时commit版本的, /// 做成protected /// </summary> /// <typeparam name="t"></typeparam> /// <param name="id"></param> public void delete<t>(int id) where t : class { t t = this.find<t>(id);//也可以附加 if (t == null) throw new exception("t is null"); this.context.set<t>().remove(t); } /// <summary> /// 删除集合 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="tlist"></param> public void delete<t>(ienumerable<t> tlist) where t : class { foreach (var t in tlist) { this.context.set<t>().attach(t); } this.context.set<t>().removerange(tlist); } #endregion #region other /// <summary> /// 一次性提交 /// </summary> public void commit() { this.context.savechanges(); } /// <summary> /// sql语句查询 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public iqueryable<t> excutequery<t>(string sql, sqlparameter[] parameters) where t : class { return this.context.database.sqlquery<t>(sql, parameters).asqueryable(); } /// <summary> /// 执行sql语句 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="sql"></param> /// <param name="parameters"></param> public void excute<t>(string sql, sqlparameter[] parameters) where t : class { dbcontexttransaction trans = null; try { trans = this.context.database.begintransaction(); this.context.database.executesqlcommand(sql, parameters); trans.commit(); } catch (exception ex) { if (trans != null) trans.rollback(); throw ex; } } public virtual void dispose() { if (this.context != null) { this.context.dispose(); } } #endregion } }
- 整合unity,实现ioc,依赖注入解决问题
虽然封装完了,但是还是带来了2个问题,问题如下代码所示,所以我们需要解决下面两个问题
问题1:通过封装,完成了通过service来完成对数据库的访问,但是右边 new studentservice()是细节,不满足依赖倒置原则,应该面向抽象编程
问题2:构造new studentservice()的时候需要一个context,不能每次都schooldbentities dbcontext = new schooldbentities();
{ schooldbentities dbcontext = new schooldbentities(); using (istudentservice istudentservice = new studentservice(dbcontext)) { student student = istudentservice.find<student>("0000000001"); student student1 = new student(); student1.student_id = "1111111"; student1.student_name = "student1"; istudentservice.insert(student1); istudentservice.commit(); } }
1、nuget引入unity相关dll
2、配置unity.config
.2.1、给baseservice注入dbcontext
<register type="system.data.entity.dbcontext, entityframework" mapto="david.general.ef.model.schooldbentities,david.general.ef.model"/>
type中逗号前是完整类型名称,也就是命名空间system.data.entity+类名dbcontext,逗号后是dll名称entityframework
mapto中逗号前是完整类型名称,也就是命名空间david.general.ef.model+类名schooldbentities,逗号后是dll名称david.general.ef.model
2.2、给istudentservice注入studentservice
<register type="david.general.ef.bussiness.interface.istudentservice,david.general.ef.bussiness.interface" mapto="david.general.ef.bussiness.service.studentservice, david.general.ef.bussiness.service">
type中逗号前是完整类型名称,也就是命名空间david.general.ef.bussiness.interface+接口名istudentservice,逗号后是dll名称david.general.ef.bussiness.interface
mapto中逗号前是完整类型名称,也就是命名空间david.general.ef.bussiness.service+类名studentservice,逗号后是dll名称david.general.ef.bussiness.service
<configuration> <configsections> <section name="unity" type="microsoft.practices.unity.configuration.unityconfigurationsection, unity.configuration"/> </configsections> <unity> <sectionextension type="microsoft.practices.unity.interceptionextension.configuration.interceptionconfigurationextension, unity.interception.configuration"/> <containers> <container name="mycontainer"> <extension type="interception"/> <register type="system.data.entity.dbcontext, entityframework" mapto="david.general.ef.model.schooldbentities,david.general.ef.model"/> <register type="david.general.ef.bussiness.interface.istudentservice,david.general.ef.bussiness.interface" mapto="david.general.ef.bussiness.service.studentservice, david.general.ef.bussiness.service"> </register> </container> </containers> </unity> </configuration>
3、调用服务
如下调用代码和截图所示
首先:我们构建学生服务的时候,没有出现细节studentservice
其次:在构建学生服务的时候,没有显式的去传入dbcontext,studentservice继承baseservice,studentservice的构造函数的参数dbcontext是来源于baseservice,而baseservice依赖的dbcontext是通过构造函数注入进来的
{ //unityconfig配置只用初始化一次,所以我们把读取unityconfig配置封装一下 //使用单例模式,l利用静态构造函数只初始化1次的特点,达到配置只初始化1次 unity.iunitycontainer container = containerfactory.getcontainer(); //ioc:去掉细节依赖,降低耦合,增强扩展性 using (istudentservice istudentservice = container.resolve<istudentservice>()) { student student = istudentservice.find<student>("0000000001"); //测试指定更新 student oldstudent = new student() { student_id = "0000020001", student_name = "猪猪",
student_sex = "男" }; list<string> filedlist = new list<string>(); filedlist.add("student_name"); istudentservice.updatespecifyfiled<student>(oldstudent, filedlist); istudentservice.commit(); }
}
namespace david.general.ef.bussiness.service { public class studentservice : baseservice,istudentservice { public studentservice(dbcontext context) : base(context) { } /// <summary> /// 记录学生打架 /// </summary> /// <param name="student"></param> public void recordstudentfight(student student) { base.insert(student); this.commit(); } } }
上一篇: 百度地图异地医保地图在哪儿?