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实现增删改查

posted @ 2014-06-27 09:48  Darren Ji  阅读(2836)  评论(11编辑  收藏  举报

我的公众号:新语新世界,欢迎关注。