企业级应用框架(二)三层架构之数据访问层的封装与抽象

  接上一篇我们来对数据访问层进行封装与抽象。在上一篇我们知道,要解除BLL对DAL的依赖,我们就必须抽象出DAL层的接口,同时基于DAL的数据访问技术很多,如EF,ADO.NET,LINQ TO SQL,因此,我们的数据访问层必须对这些技术提供相应的支持。所以今天我们要做的事情有两件,第一,定义我们的数据访问层接口;第二,屏蔽各类数据库访问技术的差异,提供统一的数据库访问模型。举个例子,我们只需要修改一下我们的配置文件,就能够把ADO.NET的实现方式,改变成EF的实现方式。好下面搭建我们的三层构,如图:

项目的框架与上一篇基本一致。项目的引用关系: StructUI->Common,Model,BLL; BLL -> Model,IDAL,Common,Factory;DAL->  IDAL,Model。再次提醒各位,我们在BLL层并没有引用DAL,我们不能创建(new)DAL层的任何实体。

下面,我们来定义DAL层的接口。定义层次的接口其实是一件很复杂的事情,首先,我们必须抽象出该层内所有对象有的属性与行为。对于数据访问层的对象,很明显增删改查是肯定走不掉的。其次我们必须充分的考虑,数据访问层各类技术对该接口的实现难度,技术上没法实现的接口,肯定是没有任何意义的。本文仅当示范作用,所以暂时我定义的接口会很简单,在后续的章节,我会抽象出一套完备的数据接口。该层的任何实体,都具备增删改查功能,所以我们首先定义该层的全局接口IDALBase<T>,即任何数据访问实体,都应该实现的接口,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IDAL
{
    public interface IDALBase<T> where T : class
    {
        /// <summary>
        /// 向T对应的数据表插入
        /// 一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>true:成功,false:失败</returns>
        bool Insert(T entity);
        /// <summary>
        /// 修改数据表中与entity
        /// 实体对应的记录
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>true:成功,false:失败</returns>
        bool Update(T entity);
        /// <summary>
        /// 删除数据表中与entity
        /// 实体对应的记录
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>true:成功,false:失败</returns>
        bool Delete(T entity);
        /// <summary>
        /// 查询数据库表中指定的ID
        /// 的记录
        /// </summary>
        /// <param name="ID">标识ID</param>
        /// <returns>指定ID记录对应的实体</returns>
        T Query(int ID);
    }
}

因为,我们的接口是面向数据访问层的所有对象,所以我们采用了范型。接着我们思考一下,除了我们全局接口所定义的方法,我们有些数据访问类可能还有一些自己特有的公共方法,这些方法也必须用接口的形式暴露出来,因为我们BLL层并没有引用DAL层,所以它是个只认接口的家伙,接口没有定义的方法,它就不会去调用,综上我们必须为每个DAL数据访问实体提供相应的接口,并且该接口里面必须涵盖数据访问类型中的所有方法,例如我定义了一个IOrder接口,如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Model;

namespace IDAL
{
    public interface IOrderDAL : IDALBase<Order>
    {
    }
}

它仅仅只是继承了全局接口,假设我们的数据访问类型Order有一个全局接口没有定义的方法如GetAllOrder(),那么在IOrder接口中必须定义出GetAllOrder()。

至此,我们的接口已经定义完成了,下面我们就要考虑封装我们的DAL了。很明显,所有的数据访问类型都继承了IDALBase<T>接口,那么有一点可以肯定,就是所有的数据访问类型都必须提供IDALBase<T>的实现代码,这个时候我们就必须设想一下,我们能否抽象出一个公共的基类,来帮我们实现IDALBase<T>接口呢?如果能的话,将极大的降低我们的代码冗余,使我们的程序变的优雅,下面我提供一个基类DALBase<T>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IDAL;

namespace DAL
{
    public class DALBase<T>:IDALBase<T> where T:class
    {
        protected IDALBase<T> dalActive;

        public bool Insert(T entity)
        {
            return dalActive.Insert(entity);
        }

        public bool Update(T entity)
        {
            return dalActive.Update(entity);
        }

        public bool Delete(T entity)
        {
            return dalActive.Delete(entity);
        }

        public T Query(int ID)
        {
            return dalActive.Query(ID);
        }
    }
}

从上面可以看到,我并没有直接在基类里面手写实现接口的代码,而是调用了基类中另一个IDALBase<T>类型的实体(dalActive)来帮助我们实现实现接口。这是为什么呢? 在前面我们说过,我们要让我们的DAL层支持各类的数据访问技术。大家想想,如果我们在基类里面,采用了一种技术如ADO.NET去把接口给实现了,那么很显然,我们这个DAL将不再支持任何其他的数据访问技术,因为我数据访问层的所有类型都继承了这个基类,基类的数据访问技术定型了,子类将根本没的选。所以我们在这里定义了一个IDALBase<T>类型的属性,让它来帮我们实现我们的接口。

在DAL层我提供了两个实现类,一个是ADOBase<T>,采用了ADO.NET技术,该类不仅仅提供给接口的实现,还提供ADO.NET操作数据库的基本API。由于该系列是我前不久才开始写的,没有现成的Doom,所以暂时只能拿出一个阉割版本了,但是该类要实现一些什么样的功能,我已经用注释说明了,在下一篇,我会提供它的具体实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IDAL;

namespace DAL
{
    public class ADOBase<T>: IDALBase<T> where T : class,new()
    {
        #region ADO.net操作数据库的基本API
        //在这一部分需要提供各类操作数据的API,作用主要有两个:
        //第一,调用这些API实现IDALBase<T>接口
        //第二,对于所有继承自DALBase<T>的数据访问层实体,
        //他会取得该dalActive实体,让后强行转换为ADOBase<T>对象
        //调用此类API,实现其特有的功能
        #endregion

        #region 实现接口
        public virtual bool Insert(T entity)
        {
            //采用ADO实现
            return true;
        }

        public virtual bool Update(T entity)
        {
            //采用ADO实现
            return true;
        }

        public virtual bool Delete(T entity)
        {
            //采用ADO实现
            return true;
        }

        public virtual T Query(int ID)
        {
            //采用ADO实现
            return new T();
        }
        #endregion
    }
}

另一个则是EFBase<T>,采用是EF技术,并提供EF操作数据库的API。供DALBase<T>子类去实现其专有的方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IDAL;

namespace DAL
{
    public class EFBase<T> : IDALBase<T> where T : class,new()
    {
        #region  EF操作数据库的API
        //这里面需要提供EF操作数据库的各类方法
        //函数
        #endregion

        #region 调用EF操作数据库的API实现接口
        public virtual bool Insert(T entity)
        {
            //采用EF
            return true;
        }

        public virtual bool Update(T entity)
        {
            //采用EF
            return true;
        }

        public virtual bool Delete(T entity)
        {
            //采用EF
            return true;
        }

        public virtual T Query(int ID)
        {
            //采用EF
            return new T();
        }
        #endregion
    }
}

好了现在基类我们有了,那么我们的子类则只需要在继承基类的同时,实例化dalActive属性,就自动的实现了IDALBase<T>接口,同时根据dalActive的类型的不同,我们的子类还具备不同的数据库访问方式(ADO.NET,EF),这是因为我们子类可以从父类的dalActive属性实体拿到其对应数据访问技术的API,我们只需强行转换一下dalActive。例如:将dalActive强转为EFBase,就可以得到EF的数据访问API(当然dalActive必须是EFBase类型)。

为了使我们的程序变的灵活,支持各类数据访问技术,我们利DalActiveProvider的静态方法来实例化我们基类中的dalActive属性,该方法通过读取配置文件来判断,给dalActive创建何种类型的实例,本文你只提供了两种实例(EFBase<T>与ADOBase<T>)所以相对简单,如下

using IDAL;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;

namespace DAL
{
    public class DalActiveProvider<T> where T:class,new()
    {
        private static string className = ConfigurationManager.AppSettings["dalActiveName"];
        public static IDALBase<T> GetDalActive()
        {
            if (string.Equals(className, "EFBase"))
            {
                return new EFBase<T>();
            }
            else
            {
                return new ADOBase<T>();
            }
        }
    }
}

下面我定义了一个OrderDAL数据访类

using Common;
using Factory;
using IDAL;
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DAL
{
    public class OrderDAL : DALBase<Order>, IOrderDAL
    {
        public OrderDAL()
        {
            this.dalActive = DalActiveProvider<Order>.GetDalActive();
        }

        #region 专有公共方法
        //根据技术的选型
        //将dalActive强行转换
        //为ADOBase<T>或者EFBase,在调用其
        //数据访问API来实现专用公共方法
        #endregion
    }
}

我们的配置文件,如图
    

很显然,目前我们会创建EFBase<T>实例给基类的dalActive属性,整个DAL层将采用EF数据访问技术,如果我们想采用ADO.NET技术的话,我们只需要将配置文件的dalActiveName的Value改为与字符创“EFBase”不等的任何字符串即可。

 至于BLL层如何调用DAL层,在我的上一篇文章已经做了详细的介绍,所以我不多说了,工厂代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Factory
{
    public class InstancesFactory
    {
        /// <summary>
        /// 创建指定类型T的实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assemblyPath">程序集路径</param>
        /// <param name="className">类名称(非全名)</param>
        /// <returns>T类型实例</returns>
        public static T CreateOrder<T>(string assemblyPath,string className)
        {
            className = string.Format("{0}.{1}", assemblyPath, className);
            return (T)Assembly.Load(assemblyPath).CreateInstance(className);
        }
    }
}

我在BLL层创建了一个很简单的基类BLLBase<T>,里面只有一个实现IDALBase<T>接口的属性dalService,如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IDAL;

namespace BLL
{
    public class BLLBase<T> where T:class
    {
        /// <summary>
        /// 数据库接口
        /// </summary>
        protected  IDALBase<T> dalService;
    }
}

在BLL的我创建一个业务子类OrderBLL继承BLLBase<T>,在构造函数中采用工厂实例化dalService,然后OrderBLL针对数据库的所有操作都是调用dalService的对应方法。当然,如果OrderBLL需要调用一些OrderDAL的专有方法,我还必须把dalService强行转换为IOrderDAL接口类型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Model;
using Factory;
using IDAL;
using Common;

namespace BLL
{
    public class OrderBLL:BLLBase<Order>
    {
        public OrderBLL()
        {
            //初始化dal服务
            this.dalService = InstancesFactory.CreateOrder<IOrderDAL>
                (FactoryConfig.Order.AssemblyPath, FactoryConfig.Order.ClassName);
        }
        public bool Inset(Order order)
        {
            //业务1
            //业务2
            return dalService.Insert(order);
        }

        #region IOrderDAL的专用方法
        public void 专用方法Dom()
        {
            IOrderDAL orderbll = dalService as IOrderDAL;
            //调用IOrderDAL的专有方法
            //orderbll.专有方法();
        }
        #endregion
    }
}

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;

namespace Common
{
    public class ConfigEntity
    {
        /// <summary>
        /// 程序路径
        /// </summary>
        public string AssemblyPath { get; set; }
        /// <summary>
        /// 类命
        /// </summary>
        public string ClassName { get; set; }
    }

    public class FactoryConfig
    {
        public static ConfigEntity Order
        {
            get
            {
                return new ConfigEntity()
                {
                    AssemblyPath=ConfigurationManager.AppSettings["AssemblyPath"],
                    ClassName = ConfigurationManager.AppSettings["ClassName"]
                };
            }
        }
    }
}

总结

  本文对数据访问层进行了概要上的封装与抽象。当然在定义接口方面我们做的很简单,在后面的章节我会完善并抽象出一个相对完备的接口,另外对于DAL的封装我们还有两大核心类(EFBase<tT>与ADOBase<T>)没有去实现,对于这两个类的实现将会是我随后的几篇博文的核心课题,最后感谢大家的观看

本文的DOME 在这里

企业级应用框架(二)三层架构之数据访问层的封装与抽象,布布扣,bubuko.com

时间: 2024-08-08 13:52:53

企业级应用框架(二)三层架构之数据访问层的封装与抽象的相关文章

企业级应用框架(三)三层架构之数据访问层的改进以及测试DOM的发布

在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.net,EF,linq To Sql,这一点我们实现的不是很完美,仍有很大的改进空间,本文将加以改进. 在此之前我们来看一下我们最新的dom(PS:经过两天的赶工,我们的dom已经相对成熟,其中BLL层已经被我高度抽象化了,并且引进了业务上文文的概念:DAL层除了具体的技术实现尚为完成,其他方面已经相

企业级应用框架(一) 三层架构之解耦

前言 前段时间朋友拿了个网站给我,让我帮忙添加几个小功能,我爽快的答应了,但是当我打开源码,我瞬间就奔溃了,整个项目连最基本的三层框架也没有搭建,仅仅是封装了一个sqlhelp作为数据库的操作接口,项目中的SQL查询语句无处不在,业务逻辑紧紧耦合在UI逻辑中,看到这样的代码,坦白来说,我什么兴致都没有了,但是碍着人情,我硬着头皮,把基本功能的完成交差,通过这件事情,我对软件分层进行了深入的思考. 三层架构 说到三层架构,大伙都很熟悉,我也不再多啰嗦了,我们直接快速搭建一个. 项目的引用关系是:S

关于面对对象过程中的三大架构以及数据访问层(实体类、数据操作类)

面向对象开发项目三层架构: 界面层.业务逻辑层.数据访问层 数据访问层,分为实体类和数据访问类 在项目的下面添加一个App_Code文件夹把所有的类放在App_Code这个文件夹下边. 一.实体类 数据库中的表映射为一个类,类名与表名一致.表中的每一列,都为该类下的成员变量和属性也就是最简单的封装 把数据库中的表名变为类的类名. 把数据库中的每一个列,变为实体类中的成员变量和属性(也就是对每个数据库中的字段封装) 列名与属性名一致.成员变量名:在列名前边加上下划线.因为在外部访问只能访问到属性,

ASP.NET 一个数据访问层的封装

刚通过开通写博客的申请,向博客园的大佬致敬,由于一直以来都在网上搜索大家的思想,也有翻遍整个百度都有的找不到的时候,作为一个网民理应为互联网贡献一点东西. 下面是我工作后受一个师傅的影响对数据库访问层的封装,多年以来一直都在使用,用的特别爽,请看下面的代码: 第一步.需要编写一个通用的用于查询的数据库存储过程,这个存储过程接受“表名.查询字段.排序.页大小.页码”: CREATE PROCEDURE [dbo].[P_Pagination] @tblName varchar(5000), --

一个用三层架构实现数据访问的例子

看了2天的三层架构,其实自己以前也看过这个,可以由于没有使用过,所以对于三层架构也只是知道罢了,昨天看了一下他一些内部的具体架构,三层分别是BLL.WEB.DAL,在web接受用户请求,bll处理业务,dal处理数据库事务,下面是一个简单的例子!这是一个添加新员工的页面: 后台代码如下: usingSystem.Collections; usingSystem.Web; usingSystem.Web.Security; usingSystem.Web.UI; usingSystem.Web.U

随机获得MySQL数据库中100条数据方法 驾照题库项目 MVC架构 biz业务层的实现类 根据考试类型rand或order通过dao数据访问层接口得到数据库中100或全部数据

package com.swift.jztk.biz; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; import com.google.gson.Gson; import com.swift.jztk.bean.Result

利用General框架进行三层架构开发

三层架构是企业信息管理系统中一种比较流行的架构方式,如大家所知,三层架构将信息系统分为数据访问层(DAL).业务逻辑层(BLL).界面表示层(UI)三部分,三层架构的好处是根据系统中代码所处的层次将系统拆开,而通过业务模型(Model)再进行连接,降低系统各层次之间的耦合度,提升程序开发和后期维护的容易度. 由于三层架构是根据由上至下的层次进行分层,而不是根据功能.应用领域进行分层,所以三层架构在每一层的关注点并不相同,数据访问层关注的是跟数据库打交道的部分,业务逻辑层关注的是业务逻辑处理部分,

JavaEE使用三层架构(显示层、业务逻辑层、数据访问层)实现数据的增删改查

实例: 1.功能描述 实现一个简易新闻发布系统,包括查看.添加.修改和删除新闻等基本功能 2.具体要求 (1) 创建数据库 newssystem,创建表 news,要求如下: (2) 程序运行时,显示'发布新闻'页面(如图 1),输入相关内容,单击'提交'按钮,将新闻内容添加到数据库 (3) 单击图 1 中的'查看'按钮,显示'查看新闻'页面(如图 2),增加'修改'和'删除'链接 (4) 单击图 2 中的'update'链接,显示'修改新闻'页面(如图 3),修改后单击'修改'按钮确认,单击'

【2017-04-20】Ado.Net与面向对象结合架构中的数据访问层(实体类,数据访问类)

开发项目三层架构:界面层.业务逻辑层.数据访问层 今天学习一下数据访问层,分为实体类和数据访问类 所有的类放在App_Code这个文件夹下边.养成一个好的习惯. 一.实体类 数据库中的表映射为一个类,类名与表名一致.表中的每一列,都为该类下的成员变量和属性也就是最简单的封装 把数据库中的表名变为类的类名. 把数据库中的每一个列,变为实体类中的成员变量和属性 列名与属性名一致.成员变量名:在列名前边加上下划线.因为在外部访问只能访问到属性,为了看起来一致. using System; using