当前位置: 移动技术网 > IT编程>开发语言>.net > EF--封装三层架构IOC

EF--封装三层架构IOC

2020年03月09日  | 移动技术网IT编程  | 我要评论

辛格里奇,申幼京,美女江山一锅煮txt下载

  • 为什么分层?

不分层封装的话,下面的代码就是上端直接依赖于下端,也就是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();
        }
    }
}

 

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网