3层数据访问架构(部分)

一、实体类是现实

实体在计算机中的表示。 它贯穿于整个架构, 负担着在各层次及模块间传递数
据的职责。一般来说,实体类可以分为“贫血实体类”和“充血实体类”,前者仅仅保存实体的
属性,而后者还包含一些体间的关系与逻辑。我们在这个 Demo 中用的实体类将是“贫血
体类”。
大多情况下, 实体类和数据库中的表 (这里指体表, 不包括表示多对多对应的关系表)
是一一对应的, 但这并不是一个限制,在复杂的数据库设计中, 有可能出现一个实体类对应
多个表,或者交叉对应的情况。在本文的 Demo 中,实体类和表是一一对应的,并且体
类中的属性和表中的字段也是对应的。
在看实体类的代码前,先看一下系统的工程结构。

image
如上图所示,在初始阶段,整个系统包括 6 个工程,它们的职责是这样的:
Web——表示层
Entity——存放实体类
Factory——存放和依赖注入及 IoC 相关的类
IBLL——存放业务逻辑层接口族
IDAL——存放数据访问层接口族
Utility——存放各种工具类及辅助类
3
这只是一个初期架构, 主要是将整个系统搭一个框架, 在后续开发中, 将会有其他工程
被陆陆续续添加进来。
我们的实体类将放在 Entity 工程下,这里包括三个文件:AdminInfo.cs,MessageInfo.
cs,CommentInfo.cs,分别是管理员实体类、留言体类和评论实体类。具体代码如下:
AdminInfo.cs:

using  System;
namespace  NGuestBook.Entity
{
    /**////  <summary>
    ///  体类-管理员
    ///  </summary>
    [Serializable]
    public  class  AdminInfo
    {
        private  int  id;
        4
            private  string  name;
        private  string  password;
        public  int  ID
        {
            get  {  return  this.id;  }
            set  {  this.id  =  value;  }
        }
        public  string  Name
        {
            get  {  return  this.name;  }
            set  {  this.name  =  value;  }
        }
        5
            public  string  Password
        {
            get  {  return  this.password;  }
            set  {  this.password  =  value;  }
        }
    }
}
MessageInfo.cs:
    MessageInfo
    using  System;
namespace  NGuestBook.Entity
{
    6
        /**////  <summary>
        ///  体类-留言
        ///  </summary>
        [Serializable]
        public  class  MessageInfo
    {
        private  int  id;
        private  string  guestName;
        private  string  guestEmail;
        private  string  content;
        private  DateTime  time;
        private  string  reply;
        private  string  isPass;
        7
            public  int  ID
        {
            get  {  return  this.id;  }
            set  {  this.id  =  value;  }
        }
        public  string  GuestName
        {
            get  {  return  this.guestName;  }
            set  {  this.guestName  =  value;  }
        }
        public  string  GuestEmail
        {
            8
                get  {  return  this.guestEmail;  }
            set  {  this.guestEmail  =  value;  }
        }
        public  string  Content
        {
            get  {  return  this.content;  }
            set  {  this.content  =  value;  }
        }
        public  DateTime  Time
        {
            get  {  return  this.time;  }
            set  {  this.time  =  value;  }
        }
        9
            public  string  Reply
        {
            get  {  return  this.reply;  }
            set  {  this.reply  =  value;  }
        }
        public  string  IsPass
        {
            get  {  return  this.isPass;  }
            set  {  this.isPass  =  value;  }
        }
    }
}

CommentInfo.cs:
CommentInfo

using  System;
namespace  NGuestBook.Entity
{
    /**////  <summary>
    ///  体类-评论
    ///  </summary>
    [Serializable]
    public  class  CommentInfo
    {
        private  int  id;
        private  string  content;
        private  DateTime  time;
        11
            private  int  message;
        public  int  ID
        {
            get  {  return  this.id;  }
            set  {  this.id  =  value;  }
        }
        public  string  Content
        {
            get  {  return  this.content;  }
            set  {  this.content  =  value;  }
        }
        public  DateTime  Time
            12
        {
            get  {  return  this.time;  }
            set  {  this.time  =  value;  }
        }
        public  int  Message
        {
            get  {  return  this.message;  }
            set  {  this.message  =  value;  }
        }
    }
}

大家可以看出, 实体类的代码很简单, 仅仅是负责体的表示和数据的传递, 不包含任
何逻辑性内容。下篇将介绍接口的设计。

接口的设计与现
接下来,将进行接口的设计。这里包括数据访问层接口和业务逻辑层接口。在分层架构中,
接口扮演着常重要的角色,它不但直接决定了各层中的各个操作类需要现何种操作,而
且它明确了各个层次的职责。接口也是系统实现依赖注入机制不可缺少的部分。
本项目的接口设计将按如下顺序进行:
1.首先由前文的需求分析,列出主要的 UI 部分。
2.分析各个 UI 需要什么业务逻辑支持,从而确定业务逻辑层接口。
3.分析业务逻辑层接口需要何种数据访问操作,从而确定数据访问层接口。
另外,为保证完全的面向对象特性,接口之间的数据传递主要靠实体类或实体类集合,
禁止使用 DataTable 等对象传递数据。
由需求分析,列出主要 UI
需求分析部分,请参看基于.NET 平台的分层架构实战(二)——需求分析与数据库设
计  。有需求分析,可以列出系统中主要应包括以下 UI:
UI01——主页面,列出全部的留言及相应评论,支持分页显示。留言按发表时间逆序
显示, 评论紧跟在相应留言下。 管理员可以通过相应链接对留言执行通过验证、 删除、 回复
以及对评论进行删除操作。游客可通过相应连接进入发表留言评论页面。
UI02——发表留言页面,供游客发表新留言。
UI03——发表评论页面,供游客发表评论。
UI04——回复留言页面,供管理员回复留言。
UI05——管理员登录页面。
UI06——管理员修改个人密码的页面。
UI07——超级管理员登录后的页面,主要提供管理员列表。可以通过相应链接将指定
管理员删除。
UI08——添加新管理员的页面。
UI09——操作成功完成后的跳转提示页面。
UI10——系统出现异常时显示友好出错信息的页面。
由 UI 识别业务逻辑操作
UI01:按分页取得留言,按指定留言取得全部评论,将指定留言通过验证,将指定留
言删除,将指定评论删除
UI02:添加新留言
UI03:添加新评论
UI04:回复留言
UI05:管理员登录
UI06:修改管理员密码
UI07:取得全部管理员信息,删除管理员
UI08:添加新管理员
经过整理,可得以下接口操作:
IAdminBLL:Add(添加管理员),Remove(删除管理员),ChangePassword(修
改管理员密码),Login(管理员登录),GetAll(取得全部管理员)
IMessageBLL:Add(添加留言),Remove(删除留言),Revert(回复留言),Pa
ss(将留言通过验证),GetByPage(按分页取得留言)
ICommentBLL:Add(添加评论),Remove(删除评论),GetByMessage(按留言
取得全部评论)
这三个接口文件都放在 IBLL 工程下,具体代码如下:

IAdminBLL.cs:
IAdminBLL

using  System;
using  System.Collections.Generic;
using  System.Text;
using  NGuestBook.Entity;
namespace  NGuestBook.IBLL
{
    /**////  <summary>
    ///  业务逻辑层接口-管理员
    ///  </summary>
    public  interface  IAdminBLL
        16
    {
        /**////  <summary>
        ///  添加管理员
        ///  </summary>
        ///  <param  name="admin">新管理员体类</param>
        ///  <returns>是否成功</returns>
        bool  Add(AdminInfo  admin);
        /**////  <summary>
        ///  删除管理员
        ///  </summary>
        ///  <param  name="id">欲删除的管理员的 ID</param>
        ///  <returns>是否成功</returns>
        bool  Remove(int  id);
        17
            /**////  <summary>
            ///  修改管理员密码
            ///  </summary>
            ///  <param  name="id">欲修改密码的管理员的 ID</param>
            ///  <param  name="password">新密码</param>
            ///  <returns>是否成功</returns>
            bool  ChangePassword(int  id,string  password);
        /**////  <summary>
        ///  管理员登录
        ///  </summary>
        ///  <param  name="name">管理员登录名</param>
        ///  <param  name="password">管理员密码</param>
        ///  <returns>如果登录成功,则返回相应管理员的实体类,否则返回 null</returns>
        18
            AdminInfo  Login(string  name,string  password);
        /**////  <summary>
        ///  取得全部管理员信息
        ///  </summary>
        ///  <returns>管理员体类集合</returns>
        IList<AdminInfo>  GetAll();
    }
}

IMessageBLL.cs:
IMessageBLL

using  System;
using  System.Collections.Generic;
using  System.Text;
 
    using  NGuestBook.Entity;
namespace  NGuestBook.IBLL
{
    /**////  <summary>
    ///  业务逻辑层接口-留言
    ///  </summary>
    public  interface  IMessageBLL
    {
        /**////  <summary>
        ///  添加留言
        ///  </summary>
        ///  <param  name="message">新留言体类</param>
        ///  <returns>是否成功</returns>
 
            bool  Add(MessageInfo  message);
        /**////  <summary>
        ///  删除留言
        ///  </summary>
        ///  <param  name="id">欲删除的留言的 ID</param>
        ///  <returns>是否成功</returns>
        bool  Remove(int  id);
        /**////  <summary>
        ///  回复留言
        ///  </summary>
        ///  <param  name="id">要回复的留言的 ID</param>
        ///  <param  name="reply">回复信息</param>
        ///  <returns>是否成功</returns>
 
            bool  Revert(int  id,  string  reply);
        /**////  <summary>
        ///  将留言通过验证
        ///  </summary>
        ///  <param  name="id">通过验证的留言的 ID</param>
        ///  <returns>是否成功</returns>
        bool  Pass(int  id);
        /**////  <summary>
        ///  按分页取得留言信息
        ///  </summary>
        ///  <param  name="pageSize">每页显示几条留言</param>
        ///  <param  name="pageNumber">当前页码</param>
        ///  <returns>留言体类集合</returns>
 
            IList<MessageInfo>  GetByPage(int  pageSize,int  pageNumber);
    }
}

ICommentBLL.cs
ICommentBLL

using  System;
using  System.Collections.Generic;
using  System.Text;
using  NGuestBook.Entity;
namespace  NGuestBook.IBLL
{
    /**////  <summary>
    ///  业务逻辑层接口-评论
    ///  </summary>
 
        public  interface  ICommentBLL
    {
        /**////  <summary>
        ///  添加评论
        ///  </summary>
        ///  <param  name="comment">新评论体类</param>
        ///  <returns>是否成功</returns>
        bool  Add(CommentInfo  comment);
        /**////  <summary>
        ///  删除评论
        ///  </summary>
        ///  <param  name="id">欲删除的评论的 ID</param>
        ///  <returns>是否成功</returns>
 
            bool  Remove(int  id);
        /**////  <summary>
        ///  取得指定留言的全部评论
        ///  </summary>
        ///  <param  name="messageId">指定留言的 ID</param>
        ///  <returns>评论体类集合</returns>
        IList<CommentInfo>  GetByMessage(int  messageId);
    }
}

由业务逻辑确定数据访问操作
IAdminBLL 需要的数据访问操作:插入管理员,删除管理员,更新管理员信息,按 ID
取得管理员信息,按登录名与密码取得管理员,取得全部管理员
IMessageBLL 需要的数据访问操作:插入留言,删除留言,更新留言信息,按 ID 取得留言
信息,按分页取得留言
ICommentBLL 需要的数据访问操作:插入评论,删除评论,按留言取得全部评论
25
另外,添加管理员时需要验证是否存在同名管理员,所以需要添加一个“按登录名取得
管理员”。
对以上操作进行整理,的如下接口操作:
IAdminDAL:Insert,Delete,Update,GetByID,GetByNameAndPassword,GetAll
IMessageDAL:Insert,Delete,Update,GetByID,GetByPage
ICommentDAL:Insert,Delete,GetByMessage
这三个接口文件放在 IDAL 工程下,具体代码如下:
IAdminDAL.cs:
IAdminDAL

using  System;
using  System.Collections.Generic;
using  System.Text;
using  NGuestBook.Entity;
namespace  NGuestBook.IDAL
{
    /**////  <summary>
    ///  数据访问层接口-管理员
 
        ///  </summary>
        public  interface  IAdminDAL
    {
        /**////  <summary>
        ///  插入管理员
        ///  </summary>
        ///  <param  name="admin">管理员体类</param>
        ///  <returns>是否成功</returns>
        bool  Insert(AdminInfo  admin);
        /**////  <summary>
        ///  删除管理员
        ///  </summary>
        ///  <param  name="id">欲删除的管理员的 ID</param>
 
            ///  <returns>是否成功</returns>
            bool  Delete(int  id);
        /**////  <summary>
        ///  更新管理员信息
        ///  </summary>
        ///  <param  name="admin">管理员体类</param>
        ///  <returns>是否成功</returns>
        bool  Update(AdminInfo  admin);
        /**////  <summary>
        ///  按 ID 取得管理员信息
        ///  </summary>
        ///  <param  name="id">管理员 ID</param>
 
            ///  <returns>管理员体类</returns>
            AdminInfo  GetByID(int  id);
        /**////  <summary>
        ///  按管理员名取得管理员信息
        ///  </summary>
        ///  <param  name="name">管理员名</param>
        ///  <returns>管理员体类</returns>
        AdminInfo  GetByName(string  name);
        /**////  <summary>
        ///  按用户名及密码取得管理员信息
        ///  </summary>
        ///  <param  name="name">用户名</param>
        ///  <param  name="password">密码</param>
 
            ///  <returns>管理员体类,不存在时返回 null</returns>
            AdminInfo  GetByNameAndPassword(string  name,string  password);
        /**////  <summary>
        ///  取得全部管理员信息
        ///  </summary>
        ///  <returns>管理员体类集合</returns>
        IList<AdminInfo>  GetAll();
    }
}

IMessageDAL.cs:
IMessageDAL

using  System;
using  System.Collections.Generic;
using  System.Text;
using  NGuestBook.Entity;
 
 
    namespace  NGuestBook.IDAL
{
    /**////  <summary>
    ///  数据访问层接口-留言
    ///  </summary>
    public  interface  IMessageDAL
    {
        /**////  <summary>
        ///  插入留言
        ///  </summary>
        ///  <param  name="message">留言体类</param>
        ///  <returns>是否成功</returns>
        bool  Insert(MessageInfo  message);
 
        /**////  <summary>
        ///  删除留言
        ///  </summary>
        ///  <param  name="id">欲删除的留言的 ID</param>
        ///  <returns>是否成功</returns>
        bool  Delete(int  id);
 
        /**////  <summary>
        ///  更新留言信息
        ///  </summary>
        ///  <param  name="message">留言体类</param>
        ///  <returns>是否成功</returns>
        bool  Update(MessageInfo  message);
 
 
        /**////  <summary>
        ///  按 ID 取得留言信息
        ///  </summary>
        ///  <param  name="id">留言 ID</param>
        ///  <returns>留言体类</returns>
        MessageInfo  GetByID(int  id);
 
        /**////  <summary>
        ///  按分页取得留言信息
        ///  </summary>
        ///  <param  name="pageSize">每页显示几条留言</param>
        ///  <param  name="pageNumber">当前页码</param>
        ///  <returns>留言体类集合</returns>
        IList<MessageInfo>  GetByPage(int  pageSize,int  pageNumber);
    }
}
 

ICommentDAL.cs:
ICommentDAL

using  System;
using  System.Collections.Generic;
using  System.Text;
using  NGuestBook.Entity;
 
namespace  NGuestBook.IDAL
{
 
    /**////  <summary>
    ///  数据访问层接口-评论
    ///  </summary>
    public  interface  ICommentDAL
    {
        /**////  <summary>
        ///  插入评论
        ///  </summary>
        ///  <param  name="comment">评论体类</param>
        ///  <returns>是否成功</returns>
        bool  Insert(CommentInfo  comment);
 
        /**////  <summary>
        ///  删除评论
        ///  </summary>
        ///  <param  name="id">欲删除的评论的 ID</param>
        ///  <returns>是否成功</returns>
        bool  Delete(int  id);
 
        /**////  <summary>
        ///  取得指定留言的全部评论
        ///  </summary>
        ///  <param  name="messageId">指定留言的 ID</param>
        ///  <returns>评论体类集合</returns>
        IList<CommentInfo>  GetByMessage(int  messageId);
    }
}

依赖注入
我们设计的分层架构, 层与层之间应该是松散耦合的。 因为是单向单一调用, 所以,这里的
“松散耦合”实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口。这
样, 上层类不能直接实例化下层中的类,而只持有接口, 至于接口所指变量最终究竟是哪一
个类,则由依赖注入机制决定。
34
之所以这样做,是为了实现层与层之间的“可替换”式设计,例如,现在需要换一种方式
现数据访问层, 只要这个实现遵循了前面定义的数据访问层接口, 业务逻辑层和表示层不
需要做任何改动,只需要改一下配置文件系统即可正常运行。另外,基于这种结构的系统,
还可以现并行开发。 即不同开发人员可以专注于自己的层次, 只有接口被定义好了, 开发
出来的东西就可以无缝连接。
在 J2EE 平台上,主要使用 Spring 框架实现依赖注入。这里,我们将自己做一个依赖
注入容器。
依赖注入的理论基础是 Abstract  Factory 设计模式,这里结合具体实例简单介绍一下。

image

上图以数据访问层为例, 展示了 Abstract  Factory 模式的应用。 如图,现假设有针对 A
ccess 和 SQLServer 两种数据库的数据访问层,它们都现了数据访问层接口。每个数据
访问层有自己的工厂,所有工厂都现自 IDALFactory 接口。而客户类(这里就是业务逻
辑层类)仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样,只要通过配置文件
确定实例化哪个工厂,就可以得到不同的数据访问层。
然而, 这种设计虽然可行, 但是代码比较冗余, 因为这样需要为数据访问层的每一个实
现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但是,.NET 平台引入的反
射机制, 给我们提供了一种解决方案。 使用反射, 每个层只需要一个工厂, 然后通过从配置
文件中读出程序集的名称, 动态加载相应类。 另外,为了提高依赖注入机制的效率,这里引
入缓存机制。下面来看具体实现。
配置
首先,需要在 Web 工程的 Web.config 文件的<appSettings>节点下添加如下两个项:
<add  key="DAL"  value=""/>
<add  key="BLL"  value=""/>
这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value 目前
是空,是因为目前还没有各个层次的具体实现。
现缓存操作辅助类
为现缓存操作, 我们将缓存操作封装成一个辅助类, 放在 Utility 工程下, 具体代码如
下:
CacheAccess.cs:
CacheAccess

using  System;
using  System.Web;
using  System.Web.Caching;
 
namespace  NGuestBook.Utility
{
    /**////  <summary>
 
    ///  辅助类,用于缓存操作
    ///  </summary>
    public  sealed  class  CacheAccess
    {
        /**////  <summary>
        ///  将对象加入到缓存中
        ///  </summary>
        ///  <param  name="cacheKey">缓存键</param>
        ///  <param  name="cacheObject">缓存对象</param>
        ///  <param  name="dependency">缓存依赖项</param>
        public  static  void  SaveToCache(string  cacheKey,  object  cacheObject,  CacheDe
 
                                          {
                                              Cache  cache  =  HttpRuntime.Cache;
                                              cache.Insert(cacheKey,  cacheObject,  dependency);
                                          }
 
                                          /**////  <summary>
 
                                          ///  </summary>
                                          ///  <param  name="cacheKey">缓存键</param>
                                          ///  <returns>获取的缓存对象</returns>
                                          public  static  object  GetFromCache(string  cacheKey)
                                          {
                                              Cache  cache  =  HttpRuntime.Cache;
 
                                              return  cache[cacheKey];
                                          }
 
        }
}

封装依赖注入代码
因为很多依赖注入代码常相似,为了减少重复性代码, 我们将可复用的代码先封装在
一个类中。具体代码如下(这个类放在 Factory 工程下):
DependencyInjector.cs:
DependencyInjector

using  System;
using  System.Configuration;
using  System.Reflection;
using  System.Web;
using  System.Web.Caching;
using  NGuestBook.Utility;
 
 
{
    /**////  <summary>
    ///  依赖注入提供者
    ///  使用反射机制现
    ///  </summary>
    public  sealed  class  DependencyInjector
    {
        /**////  <summary>
        ///  取得数据访问层对象
        ///  首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
        ///  </summary>
 
        ///  <param  name="className">数据访问类名称</param>
        ///  <returns>数据访问层对象</returns>
        public  static  object  GetDALObject(string  className)
        {
            /**////  <summary>
            ///  取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取
 
            ///  </summary>
            object  dal  =  CacheAccess.GetFromCache("DAL");
            if  (dal  ==  null)
            {
                CacheDependency  fileDependency  =  new  CacheDependency(HttpConte
                                                                         .Current.Server.MapPath("Web.Config"));
                dal  =  ConfigurationManager.AppSettings["DAL"];
                CacheAccess.SaveToCache("DAL",  dal,  fileDependency);
            }
 
            /**////  <summary>
            ///  取得数据访问层对象
            ///  </summary>
            string  dalName  =  (string)dal;
            string  fullClassName  =  dalName  +  "."  +  className;
            object  dalObject  =  CacheAccess.GetFromCache(className);
            if  (dalObject  ==  null)
            {
                CacheDependency  fileDependency  =  new  CacheDependency(HttpConte
                                                                         .Current.Server.MapPath("Web.Config"));
                dalObject  =  Assembly.Load(dalName).CreateInstance(fullClassName);
 
                CacheAccess.SaveToCache(className,  dalObject,  fileDependency);
            }
 
            return  dalObject;
        }
 
        /**////  <summary>
        ///  取得业务逻辑层对象
        ///  首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
        ///  </summary>
        ///  <param  name="className">业务逻辑类名称</param>
        ///  <returns>业务逻辑层对象</returns>
        public  static  object  GetBLLObject(string  className)
        {
            /**////  <summary>
            ///  取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取
            ///  缓存依赖项为 Web.Config 文件
            ///  </summary>
            object  bll  =  CacheAccess.GetFromCache("BLL");
            if  (bll  ==  null)
            {
                CacheDependency  fileDependency  =  new  CacheDependency(HttpConte
                                                                         .Current.Server.MapPath("Web.Config"));
                bll  =  ConfigurationManager.AppSettings["BLL"];
                CacheAccess.SaveToCache("BLL",  bll,  fileDependency);
            }
 
            /**////  <summary>
 
            ///  取得业务逻辑层对象
            ///  </summary>
            string  bllName  =  (string)bll;
            string  fullClassName  =  bllName  +  "."  +  className;
            object  bllObject  =  CacheAccess.GetFromCache(className);
            if  (bllObject  ==  null)
            {
                CacheDependency  fileDependency  =  new  CacheDependency(HttpConte
                                                                         .Current.Server.MapPath("Web.Config"));
                bllObject  =  Assembly.Load(bllName).CreateInstance(fullClassName);
                CacheAccess.SaveToCache(className,  bllObject,  fileDependency);
            }
 
            return  bllObject;
        }
    }
}

现工厂
下面使用两个辅助类,实现数据访问层工厂和业务逻辑层工厂。
DALFactory.cs
DALFactory

using  System;
using  NGuestBook.IDAL;
#VALUE!
namespace  NGuestBook.Factory
{
    #VALUE!
    /**////  <summary>
    ///  数据访问层工厂,用于获取相应的数据访问层对象
    ///  使用 Abstract  Factory 设计模式+Facace 设计模式+反射机制+缓存机制设计
    ///  </summary>
    public  sealed  class  DALFactory
    {
        /**////  <summary>
        ///  获取管理员数据访问层对象
        ///  </summary>
        ///  <returns>管理员数据访问层对象</returns>
        public  static  IAdminDAL  CreateAdminDAL()
        {
            return  (IAdminDAL)DependencyInjector.GetDALObject("AdminDAL");
        }
        #VALUE!
        /**////  <summary>
        ///  获取留言数据访问层对象
        ///  </summary>
        ///  <returns>留言数据访问层对象</returns>
        public  static  IMessageDAL  CreateMessageDAL()
        {
            return  (IMessageDAL)DependencyInjector.GetDALObject("MessageDAL");
        }
        #VALUE!
        /**////  <summary>
        ///  获取评论数据访问层对象
        ///  </summary>
        ///  <returns>评论数据访问层对象</returns>
        #VALUE!
        public  static  ICommentDAL  CreateCommentDAL()
        {
            return  (ICommentDAL)DependencyInjector.GetDALObject("CommentDAL");
        }
    }
}

BLLFactory.cs
BLLFactory

using  System;
using  NGuestBook.IBLL;
#VALUE!
namespace  NGuestBook.Factory
{
    /**////  <summary>
    ///  业务逻辑层工厂,用于获取相应的业务逻辑层对象
    ///  使用 Abstract  Factory 设计模式+Facace 设计模式+反射机制+缓存机制设计
    ///  </summary>
    0  public  sealed  class  BLLFactory
    {
        /**////  <summary>
        ///  获取管理员业务逻辑层对象
        ///  </summary>
        ///  <returns>管理员业务逻辑层对象</returns>
        public  static  IAdminBLL  CreateAdminBLL()
        {
            return  (IAdminBLL)DependencyInjector.GetBLLObject("AdminBLL");
            #VALUE!
        }
        #VALUE!
        /**////  <summary>
        ///  获取留言业务逻辑层对象
        ///  </summary>
        ///  <returns>留言业务逻辑层对象</returns>
        public  static  IMessageBLL  CreateMessageBLL()
        {
            return  (IMessageBLL)DependencyInjector.GetBLLObject("MessageBLL");
        }
        #VALUE!
        /**////  <summary>
        ///  获取评论业务逻辑层对象
        ///  </summary>
        ///  <returns>评论业务逻辑层对象</returns>
        public  static  ICommentBLL  CreateCommentBLL()
        {
            return  (ICommentBLL)DependencyInjector.GetBLLObject("CommentBLL");
        }
    }
}
}

数据访问实现方法一:ACCESS+SQL
经过上面篇文章的介绍, 整个系统的框架算是基本搭建完了, 下面, 我们要具体实现各个层
次。关于数据访问层的实现,我准备讨论三种实现方式,这一篇文章讨论第一种:Access
+动态生成 SQL。
顾名思义,这种现将使用 Access 作为后台数据库,而操作方式也是最基本的使用 S
QL 命令。
在具体编写现代码之前,我们需要做一些准备工作:
第一步,我们要将 Access 数据库搭建完成,具体做法如下。
45
在 Web 工程下新建一个文件夹, 命名为 AccessData, 并在其中新建一个 mdb 文件(即
Access 数据库文件),按照前面介绍过的数据库设计构架,将数据表及表间关系建好,这
里不再赘述。
第二步,我们要进行一些配置。
打开 Web 工程下的 Web.config 文件,在其中的 appSettings 节点下,添加如下键值:

显示行号 复制代码 这是一段程序代码。
  1. <add  key="AccessConnectionString"  value="Provider=Microsoft.Jet.OLEDB.4.0;
  2. Data  Source={DBPath}"/> 
  3. <add  key="AccessPath"  value="~/AccessData/AccessDatabase.mdb"/>

第一条为 Access 的连接字符串,第二条为 Access 数据库文件的路径,其中“~”表示网
站根目录。
第三步,新建一个工程。
我们要新建一个工程 AccessDAL,用来存放 Access 数据访问层的代码。
准备工作做完了,现在来现具体的代码。
1.编写数据访问助手类
因为很多数据访问操作流程很相似, 所以,这里将一些可复用的代码抽取出来, 编写成
助手类,以此减少代码量,提高代码复用性。
这个助手类放在 AccessDAL 下, 叫 AccessDALHelper,主要负责 Access 数据库的访
问。它包括三个方法:
GetConnectionString:从配置文件中读取配置项,组合成连接字符串。
ExecuteSQLNonQuery:执行指定 SQL 语句,不返回任何值,一般用于 Insert,Delet
e,Update 命令。
ExecuteSQLDataReader:执行 SQL 语句返回查询结果,一般用于 Select 命令。
46
具体代码如下:
AccessDALHelper.cs:
AccessDALHelper

using  System;
using  NGuestBook.IBLL;
#VALUE!
namespace  NGuestBook.Factory
{
    /**////  <summary>
    ///  业务逻辑层工厂,用于获取相应的业务逻辑层对象
    ///  使用 Abstract  Factory 设计模式+Facace 设计模式+反射机制+缓存机制设计
    ///  </summary>
    public  sealed  class  BLLFactory
    {
        /**////  <summary>
        ///  获取管理员业务逻辑层对象
        ///  </summary>
        ///  <returns>管理员业务逻辑层对象</returns>
        public  static  IAdminBLL  CreateAdminBLL()
        {
            return  (IAdminBLL)DependencyInjector.GetBLLObject("AdminBLL");
 
        }
 
        /**////  <summary>
        ///  获取留言业务逻辑层对象
        ///  </summary>
        ///  <returns>留言业务逻辑层对象</returns>
        public  static  IMessageBLL  CreateMessageBLL()
        {
            return  (IMessageBLL)DependencyInjector.GetBLLObject("MessageBLL");
        }
 
        /**////  <summary>
        ///  获取评论业务逻辑层对象
        ///  </summary>
        ///  <returns>评论业务逻辑层对象</returns>
        public  static  ICommentBLL  CreateCommentBLL()
        {
            return  (ICommentBLL)DependencyInjector.GetBLLObject("CommentBLL");
        }
    }
}
}

2.现具体的数据访问操作类
因为前面已经定义了数据访问层接口,所以实现数据访问操作类就是很机械的工作了。
下面仅以 Admin 的数据访问操作类为例:
AdminDAL:
AdminDAL

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Data;
using  System.Data.OleDb;
using  NGuestBook.IDAL;
using  NGuestBook.Entity;
 
 
amespace  NGuestBook.AccessDAL
{
    public  class  AdminDAL  :  IAdminDAL
    {
        /**////  <summary>
        ///  插入管理员
        ///  </summary>
        ///  <param  name="admin">管理员体类</param>
        ///  <returns>是否成功</returns>
        public  bool  Insert(AdminInfo  admin)
        {
            string  SQLCommand  =  "insert  into  [TAdmin]([Name],[Password])  values(@name,@password)";
            #VALUE!
            OleDbParameter[]  parameters  ={
                new  OleDbParameter("name",admin.Name),
                new  OleDbParameter("password",admin.Password)
            };
 
            try
            {
                AccessDALHelper.ExecuteSQLNonQuery(SQLCommand,  parameters);
                return  true;
            }
            catch
            {
                return  false;
            }
 
        }
 
        /**////  <summary>
        ///  删除管理员
        ///  </summary>
        ///  <param  name="id">欲删除的管理员的 ID</param>
        ///  <returns>是否成功</returns>
        public  bool  Delete(int  id)
        {
            string  SQLCommand  =  "delete  from  [TAdmin]  where  [ID]=@id";
            OleDbParameter[]  parameters  ={
                new  OleDbParameter("id",id)
            };
 
            try
            {
                AccessDALHelper.ExecuteSQLNonQuery(SQLCommand,  parameters);
                return  true;
            }
            catch
            {
                return  false;
            }
        }
 
        /**////  <summary>
        ///  更新管理员信息
        ///  </summary>
 
        ///  <param  name="admin">管理员体类</param>
        ///  <returns>是否成功</returns>
        public  bool  Update(AdminInfo  admin)
        {
            string  SQLCommand  =  "update  [TAdmin]  set  [Name]=@name,[Password]=@password  where  [ID]=@id";
            #VALUE!
            OleDbParameter[]  parameters  ={
                new  OleDbParameter("id",admin.ID),
                new  OleDbParameter("name",admin.Name),
                new  OleDbParameter("password",admin.Password)
            };
 
            try
            {
                AccessDALHelper.ExecuteSQLNonQuery(SQLCommand,  parameters);
                return  true;
            }
            catch
            {
                return  false;
            }
        }
 
        /**////  <summary>
 
        ///  </summary>
        ///  <param  name="id">管理员 ID</param>
        ///  <returns>管理员体类</returns>
 
        public  AdminInfo  GetByID(int  id)
        {
            string  SQLCommand  =  "select  *  from  [TAdmin]  where  [ID]=@id";
            OleDbParameter[]  parameters  ={
                new  OleDbParameter("id",id)
            };
 
            try
            {
                OleDbDataReader  dataReader  =  AccessDALHelper.ExecuteSQLDataReader(SQLCommand,  parameters);
                #VALUE!
                if  (!dataReader.HasRows)
                {
                    throw  new  Exception();
                }
 
                AdminInfo  admin  =  new  AdminInfo();
                dataReader.Read();
                admin.ID=(int)dataReader["ID"];
                admin.Name=(string)dataReader["Name"];
                admin.Password=(string)dataReader["Password"];
 
                return  admin;
            }
            catch
            {
                return  null;
            }
 
        }
 
        /**////  <summary>
        ///  按用户名及密码取得管理员信息
        ///  </summary>
        ///  <param  name="name">用户名</param>
        ///  <param  name="password">密码</param>
        ///  <returns>管理员体类,不存在时返回 null</returns>
        public  AdminInfo  GetByNameAndPassword(string  name,  string  password)
        {
            string  SQLCommand  =  "select  *  from  [TAdmin]  where  [Name]=@name
                [Password]=@password";
                OleDbParameter[]  parameters  ={
                new  OleDbParameter("name",name),
                new  OleDbParameter("password",password),
            };
 
            try
            {
                OleDbDataReader  dataReader  =  AccessDALHelper.ExecuteSQLDataReader(SQLCommand,  parameters);
                #VALUE!
                if  (!dataReader.HasRows)
                {
                    throw  new  Exception();
                }
 
                AdminInfo  admin  =  new  AdminInfo();
                dataReader.Read();
 
                admin.ID  =  (int)dataReader["ID"];
                admin.Name  =  (string)dataReader["Name"];
                admin.Password  =  (string)dataReader["Password"];
 
                return  admin;
            }
            catch
            {
                return  null;
            }
        }
 
        /**////  <summary>
        ///  按管理员名取得管理员信息
        ///  </summary>
        ///  <param  name="name">管理员名</param>
        ///  <returns>管理员体类</returns>
        public  AdminInfo  GetByName(string  name)
        {
            string  SQLCommand  =  "select  *  from  [TAdmin]  where  [Name]=@name";
            OleDbParameter[]  parameters  ={
                new  OleDbParameter("name",name),
            };
 
            try
            {
                OleDbDataReader  dataReader  =  AccessDALHelper.ExecuteSQLDataReader(SQLCommand,  parameters);
                #VALUE!
 
                if  (!dataReader.HasRows)
                {
                    throw  new  Exception();
                }
 
                AdminInfo  admin  =  new  AdminInfo();
                dataReader.Read();
                admin.ID  =  (int)dataReader["ID"];
                admin.Name  =  (string)dataReader["Name"];
                admin.Password  =  (string)dataReader["Password"];
 
                return  admin;
            }
            catch
            {
                return  null;
            }
        }
 
        /**////  <summary>
        ///  取得全部管理员信息
        ///  </summary>
        ///  <returns>管理员体类集合</returns>
        public  IList<AdminInfo>  GetAll()
        {
            string  SQLCommand  =  "select  *  from  [TAdmin]";
            try
            {
 
                OleDbDataReader  dataReader  =  AccessDALHelper.ExecuteSQLDataReader(SQLCommand,  null);
                #VALUE!
                if  (!dataReader.HasRows)
                {
                    throw  new  Exception();
                }
 
                IList<AdminInfo>  adminCollection  =  new  List<AdminInfo>();
                int  i  =  0;
                while  (dataReader.Read())
                {
                    AdminInfo  admin  =  new  AdminInfo();
                    admin.ID  =  (int)dataReader["ID"];
                    admin.Name  =  (string)dataReader["Name"];
                    admin.Password  =  (string)dataReader["Password"];
 
                    adminCollection.Add(admin);
                    i++;
                }
 
                return  adminCollection;
            }
            catch
            {
                return  null;
            }
        }
 
    }
}
原文地址:https://www.cnblogs.com/sczw-maqing/p/3369131.html