zoukankan      html  css  js  c++  java
  • MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层

    SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器、URL优化、导航、分页、购物车、订单、产品管理、图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离。本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能。

    本篇为系列第二篇,包括:

    ■ 4、三层架构设计
        □ 4.2 创建DbSession层 数据访问层的统一入口 
            ※ 4.2.1 MySportsStore.IDAL详解
            ※ 4.2.2 MySportsStore.DAL详解
        □ 4.3 创建BLL层       
            ※ 4.3.1 MySportsStore.IBLL详解
            ※ 4.3.2 MySportsStore.BLL详解
           

      4.2 创建DbSession层 数据访问层的统一入口

    DbSession层主要做了3件事:
    1、提交所有变化
    2、拿到各个IXXXRepository类型
    3、执行SQL语句

      4.2.1 MySportsStore.IDAL详解

    →IDbSession接口,数据库访问层的统一入口

    using System.Data.SqlClient;
    
    namespace MySportsStore.IDAL
    {
        public interface IDbSession
        {
            //获取所有的仓储接口
            IProductRepository ProductRepository { get; set; }
            
            //保存所有变化
            int SaveChanges();
    
            //执行sql语句
            int ExeucteSql(string sql, params SqlParameter[] paras);
        }
    }

    →IDbSessionFactory接口,IDbSession接口的抽象工厂

    在BaseRepository中会用到IDbSession的实例,我们借助"抽象工厂"生产IDbSession的实例。

    namespace MySportsStore.IDAL
    {
        public interface IDbSessionFactory
        {
            IDbSession GetCurrentDbSession();
        }
    }

      4.2.2 MySportsStore.DAL详解

    →DbSession,对IDbSession接口的实现

    using System.Data.Entity;
    using MySportsStore.IDAL;
    
    namespace MySportsStore.DAL
    {
        public class DbSession : IDbSession
        {
            private IProductRepository _ProductRepository;
            public IProductRepository ProductRepository
            {
                get
                {
                    if (_ProductRepository == null)
                    {
                        _ProductRepository = new ProductRepository();
                    }
                    return _ProductRepository;
                }
                set { _ProductRepository = value; }
            }
    
            public int SaveChanges()
            {
                IDbContextFactory dbFactory = new DbContextFactory();
                DbContext db = dbFactory.GetCurrentThreadInstance();
                return db.SaveChanges();
            }
    
            public int ExeucteSql(string sql, params System.Data.SqlClient.SqlParameter[] paras)
            {
                IDbContextFactory dbFactory = new DbContextFactory();
                DbContext db = dbFactory.GetCurrentThreadInstance();
                return db.Database.ExecuteSqlCommand(sql, paras);
            }
        }
    }

    →DbSessionFactory,实现IDbSessionFactory接口,生产线程内唯一数据层访问入口实例

    using System.Runtime.Remoting.Messaging;
    using MySportsStore.IDAL;
    
    namespace MySportsStore.DAL
    {
        public class DbSessionFactory: IDbSessionFactory
        {
            public IDbSession GetCurrentDbSession()
            {
                IDbSession dbSession = CallContext.GetData(typeof (DbSession).FullName) as IDbSession;
                if (dbSession == null)
                {
                    dbSession = new DbSession();
                    CallContext.SetData(typeof(DbSession).FullName, dbSession);
                }
                return dbSession;
            }
        }
    }

      4.3 创建BLL层

      4.3.1 MySportsStore.IBLL详解

    →添加引用

    ● 添加对MySportsStore.Model的引用
    ● 添加对MySportsStore.IDAL的引用

    →IBaseService,是所有IXXXService接口的泛型基接口实现,避免了所有IXXXService接口的重复部分

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using MySportsStore.IDAL;
    
    namespace MySportsStore.IBLL
    {
        public interface IBaseService<T> where T : class, new()
        {
             //数据层访问统一入口工厂
            IDbSessionFactory DbSessionFactory { get; set; }
    
            //数据层访问统一入口
            IDbSession DbSessionContext { get; set; }
    
            //查询
            IQueryable<T> LoadEntities(Expression<Func<T, bool>> whereLambda);
    
            //分页查询
            IQueryable<T> LoadPageEntities<S>(
                Expression<Func<T, bool>> whereLambada,
                Expression<Func<T, S>> orderBy,
                int pageSize,
                int pageIndex,
                out int totalCount,
                bool isASC);
    
            //查询总数量
            int Count(Expression<Func<T, bool>> predicate);
    
            //添加
            T AddEntity(T entity);
    
            //批量添加
            int AddEntities(params T[] entities);
    
            //删除
            int DeleteEntity(T entity);
    
            //批量删除
            int DeleteBy(Expression<Func<T, bool>> whereLambda);
    
            //更新
            T UpdateEntity(T entity);
    
            //批量更新
            int UpdateEntities(params T[] entities);
        }
    }

    为什么需要DbSessionContext属性?
    --通过该属性可以拿到类型为IXXXRepository的XXXRepository。

    为什么需要DbSessionFactory属性?
    --通过该"抽象工厂"属性可以生产DbSessionContext实例。

    →IProductService,对基接口IBaseService<Product>的实现

    using MySportsStore.Model;
    
    namespace MySportsStore.IBLL
    {
        public interface IProductService : IBaseService<Product>
        {
             
        }
    }

      4.3.2 MySportsStore.BLL详解

    →添加引用

    ● 添加对MySportsStore.Model的引用
    ● 添加对MySportsStore.IDAL的引用
    ● 添加对MySportsStore.IBLL的引用

    →BaseService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using MySportsStore.DAL;
    using MySportsStore.IDAL;
    
    namespace MySportsStore.BLL
    {
        public abstract class BaseService<T> : IDisposable where T:class,new()
        {
            //数据层统一访问入口工厂属性
            private IDbSessionFactory _DbSessionFactory;
    
            public IDbSessionFactory DbSessionFactory
            {
                get
                {
                    if (_DbSessionFactory == null)
                    {
                        _DbSessionFactory = new DbSessionFactory();
                    }
                    return _DbSessionFactory;
                }
                set { _DbSessionFactory = value; }
            }
    
            //数据层统一访问入口属性
            private IDbSession _DbSessionContext;
    
            public IDbSession DbSessionContext
            {
                get
                {
                    if (_DbSessionContext == null)
                    {
                        _DbSessionContext = DbSessionFactory.GetCurrentDbSession();
                    }
                    return _DbSessionContext;
                }
                set { _DbSessionContext = value; }
            }
    
            //当前Repository,在子类中实现--通过一个抽象方法在构造函数中设置
            protected IBaseRepository<T> CurrentRepository;
    
            //借助此方法在子类中的重写,为XXXService设置当前Repository
            public abstract bool SetCurrentRepository();
    
            public BaseService()
            {
                this.DisposableObjects = new List<IDisposable>();
                this.SetCurrentRepository();
            }
    
            //查询
            public IQueryable<T> LoadEntities(Expression<Func<T, bool>> whereLambda)
            {
                return this.CurrentRepository.LoadEntities(whereLambda);
            }
    
            public IQueryable<T> LoadPageEntities<S>(
                Expression<Func<T, bool>> whereLambada,
                Expression<Func<T, S>> orderBy,
                int pageSize,
                int pageIndex,
                out int totalCount,
                bool isASC)
            {
                return this.CurrentRepository.LoadPageEntities<S>(
                    whereLambada,
                    orderBy,
                    pageSize,
                    pageIndex,
                    out totalCount,
                    isASC);
            }
    
            //查询总数量
            public int Count(Expression<Func<T, bool>> predicate)
            {
                return this.CurrentRepository.Count(predicate);
            }
    
            //添加
            public T AddEntity(T entity)
            {
                this.CurrentRepository.AddEntity(entity);
                DbSessionContext.SaveChanges();
                return entity;
            }
    
            //批量添加
            public int AddEntities(params T[] entities)
            {
                return this.CurrentRepository.AddEntities(entities);
            }
    
            //删除
            public int DeleteEntity(T entity)
            {
                this.CurrentRepository.DeleteEntity(entity);
                return DbSessionContext.SaveChanges();
            }
    
            //批量删除
            public int DeleteBy(Expression<Func<T, bool>> whereLambda)
            {
                this.CurrentRepository.DeleteBy(whereLambda);
                return DbSessionContext.SaveChanges();
            }
    
            //更新
            public T UpdateEntity(T entity)
            {
                this.CurrentRepository.UpdateEntity(entity);
                if (this.DbSessionContext.SaveChanges() <= 0)
                {
                    return null;
                }
                return entity;
            }
    
            //批量更新
            public int UpdateEntities(params T[] entities)
            {
                return this.CurrentRepository.UpdateEntities(entities);
            }
    
            public IList<IDisposable> DisposableObjects { get; private set; }
    
            protected void AddDisposableObject(object obj)
            {
                IDisposable disposable = obj as IDisposable;
                if (disposable != null)
                {
                    this.DisposableObjects.Add(disposable);
                }
            }
    
            public void Dispose()
            {
                foreach (IDisposable obj in this.DisposableObjects)
                {
                    if (obj != null)
                    {
                        obj.Dispose();
                    }
                }
            }
        }
    }

    BaseService是所有XXXService的泛型基类实现。

    关键点一:如何在BaseService的子类中确定当前存储CurrentRepository?
    1、抽象基类BaseServic有类型为 IBaseRepository<T>的属性CurrentRepository
    2、通过在抽象基类BaseServic的构造函数中实现抽象方法SetCurrentRepository(),来设置CurrentRepository
    3、BaseServic的子类必须重写SetCurrentRepository()以最终确定当前的CurrentRepository值


    关键点二:如何把BaseService的子类中的CurrentRepository销毁?
    1、在BaseService创建一个类型为IList<IDisposable>的集合
    2、在BaseService中提供一个AddDisposableObject(object obj)方法,允许子类把CurrentRepository放入其中
    3、在BaseService的Dispose()方法中,遍历所有的CurrentRepository进行销毁

    →ProductService,派生于BaseService<Product>,实现IProductService接口

    using MySportsStore.IBLL;
    using MySportsStore.Model;
    
    namespace MySportsStore.BLL
    {
        public class ProductService : BaseService<Product>, IProductService
        {
            public ProductService():base(){}
    
            public override bool SetCurrentRepository()
            {
                this.CurrentRepository = DbSessionContext.ProductRepository;
                this.AddDisposableObject(this.CurrentRepository);
                return true;
            }
        }
    }

    至此,完成了三层架构的代码实现。

    源码在这里

    “MVC项目实践,在三层架构下实现SportsStore”系列包括:

    MVC项目实践,在三层架构下实现SportsStore,从类图看三层架构

    MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等

    MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层

    MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等

    MVC项目实践,在三层架构下实现SportsStore-04,实现分页

    MVC项目实践,在三层架构下实现SportsStore-05,实现导航

    MVC项目实践,在三层架构下实现SportsStore-06,实现购物车

    MVC项目实践,在三层架构下实现SportsStore-07,实现订单提交

    MVC项目实践,在三层架构下实现SportsStore-08,部署到IIS服务器

    MVC项目实践,在三层架构下实现SportsStore-09,ASP.NET MVC调用ASP.NET Web API的查询服务

    MVC项目实践,在三层架构下实现SportsStore-10,连接字符串的加密和解密

    MVC项目实践,在三层架构下实现SportsStore-11,使用Knockout实现增删改查

  • 相关阅读:
    散列函数之单散列算法
    NET 使用 RabbitMQ
    leetCode
    Swift 1
    C#并发集合
    多进程与多线程1
    开发编译器
    APUE1
    微服务架构
    ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”
  • 原文地址:https://www.cnblogs.com/darrenji/p/3811319.html
Copyright © 2011-2022 走看看