3层数据访问架构(部分)
一、实体类是现实
实体在计算机中的表示。 它贯穿于整个架构, 负担着在各层次及模块间传递数
据的职责。一般来说,实体类可以分为“贫血实体类”和“充血实体类”,前者仅仅保存实体的
属性,而后者还包含一些体间的关系与逻辑。我们在这个 Demo 中用的实体类将是“贫血
体类”。
大多情况下, 实体类和数据库中的表 (这里指体表, 不包括表示多对多对应的关系表)
是一一对应的, 但这并不是一个限制,在复杂的数据库设计中, 有可能出现一个实体类对应
多个表,或者交叉对应的情况。在本文的 Demo 中,实体类和表是一一对应的,并且体
类中的属性和表中的字段也是对应的。
在看实体类的代码前,先看一下系统的工程结构。
如上图所示,在初始阶段,整个系统包括 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 设计模式,这里结合具体实例简单介绍一下。
上图以数据访问层为例, 展示了 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 节点下,添加如下键值:
-
<add key="AccessConnectionString" value="Provider=Microsoft.Jet.OLEDB.4.0;
-
Data Source={DBPath}"/>
-
<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;
}
}
}
}