zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    }

  • 相关阅读:
    一个很吊的swing循环生成窗口。
    hbase操作的问题
    hadoop+hbase
    linux故障救援
    管道命令xargs
    hadoop浅尝 hadoop与hbase交互
    linux源代码阅读笔记 free_page_tables()分析
    词法分析器flex的使用
    每天一个Linux命令(1): find
    梯度下降
  • 原文地址:https://www.cnblogs.com/menglin2010/p/12273068.html
Copyright © 2011-2022 走看看