MVC專案實踐,在三層架構下實現SportsStore-02,DbSession層、BLL層

Darren Ji發表於2014-06-27

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實現增刪改查

相關文章