欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

EF--封装三层架构IOC

程序员文章站 2022-05-03 10:56:57
为什么分层? 不分层封装的话,下面的代码就是上端直接依赖于下端,也就是UI层直接依赖于数据访问层,分层一定要依赖抽象,满足依赖倒置原则,所以我们要封装,要分层 下面这张图和传统的三层略有不同,不同之处在于,UI层不直接依赖于业务逻辑层,而是UI层依赖于业务逻辑抽象层IBLL,业务逻辑层不直接依赖于数 ......
  • 为什么分层?

不分层封装的话,下面的代码就是上端直接依赖于下端,也就是ui层直接依赖于数据访问层,分层一定要依赖抽象,满足依赖倒置原则,所以我们要封装,要分层

下面这张图和传统的三层略有不同,不同之处在于,ui层不直接依赖于业务逻辑层,而是ui层依赖于业务逻辑抽象层ibll,业务逻辑层不直接依赖于数据访问层,而是业务逻辑层依赖于数据访问抽象层idal

{
    schooldbentities dbcontext = new schooldbentities();
    dbcontext.set<student>().where(s=>s.student_id == "0000000001");
}

EF--封装三层架构IOC

  • 封装分层

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

EF--封装三层架构IOC

EF--封装三层架构IOC

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();
        }
    }
}

EF--封装三层架构IOC

 

EF--封装三层架构IOC