有没有人可以帮忙写代码(C#,mvc三层架构开发模式)

&>&C#三层架构代码生成器
C#三层架构代码生成器
上传大小:141KB
C#三层架构代码基层类生成器,可用C#虚拟机运行,也可放置C#开发工具运行。
综合评分:4
{%username%}回复{%com_username%}{%time%}\
/*点击出现回复框*/
$(".respond_btn").on("click", function (e) {
$(this).parents(".rightLi").children(".respond_box").show();
e.stopPropagation();
$(".cancel_res").on("click", function (e) {
$(this).parents(".res_b").siblings(".res_area").val("");
$(this).parents(".respond_box").hide();
e.stopPropagation();
/*删除评论*/
$(".del_comment_c").on("click", function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_invalid/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parents(".conLi").remove();
alert(data.msg);
$(".res_btn").click(function (e) {
var parentWrap = $(this).parents(".respond_box"),
q = parentWrap.find(".form1").serializeArray(),
resStr = $.trim(parentWrap.find(".res_area_r").val());
console.log(q);
//var res_area_r = $.trim($(".res_area_r").val());
if (resStr == '') {
$(".res_text").css({color: "red"});
$.post("/index.php/comment/do_comment_reply/", q,
function (data) {
if (data.succ == 1) {
var $target,
evt = e || window.
$target = $(evt.target || evt.srcElement);
var $dd = $target.parents('dd');
var $wrapReply = $dd.find('.respond_box');
console.log($wrapReply);
//var mess = $(".res_area_r").val();
var mess = resS
var str = str.replace(/{%header%}/g, data.header)
.replace(/{%href%}/g, 'http://' + window.location.host + '/user/' + data.username)
.replace(/{%username%}/g, data.username)
.replace(/{%com_username%}/g, data.com_username)
.replace(/{%time%}/g, data.time)
.replace(/{%id%}/g, data.id)
.replace(/{%mess%}/g, mess);
$dd.after(str);
$(".respond_box").hide();
$(".res_area_r").val("");
$(".res_area").val("");
$wrapReply.hide();
alert(data.msg);
}, "json");
/*删除回复*/
$(".rightLi").on("click", '.del_comment_r', function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_comment_del/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parent().parent().parent().parent().parent().remove();
$(e.target).parents('.res_list').remove()
alert(data.msg);
//填充回复
function KeyP(v) {
var parentWrap = $(v).parents(".respond_box");
parentWrap.find(".res_area_r").val($.trim(parentWrap.find(".res_area").val()));
评论共有10条
这个不能直接使用。 有点问题。还需自己改进
有点乱,还需完善,在上面改。
有点乱,看不太懂,不过还是谢谢!
xiaocui0601
综合评分:
积分/C币:3
zaishijieshang
综合评分:
积分/C币:3
VIP会员动态
CSDN下载频道资源及相关规则调整公告V11.10
下载频道用户反馈专区
下载频道积分规则调整V1710.18
spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip
资源所需积分/C币
当前拥有积分
当前拥有C币
输入下载码
为了良好体验,不建议使用迅雷下载
C#三层架构代码生成器
会员到期时间:
剩余下载个数:
剩余积分:0
为了良好体验,不建议使用迅雷下载
积分不足!
资源所需积分/C币
当前拥有积分
您可以选择
程序员的必选
绿色安全资源
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
无法举报自己的资源
你当前的下载分为234。
你还不是VIP会员
开通VIP会员权限,免积分下载
你下载资源过于频繁,请输入验证码
您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:!
若举报审核通过,可返还被扣除的积分
被举报人:
请选择类型
资源无法下载 ( 404页面、下载失败、资源本身问题)
资源无法使用 (文件损坏、内容缺失、题文不符)
侵犯版权资源 (侵犯公司或个人版权)
虚假资源 (恶意欺诈、刷分资源)
含色情、危害国家安全内容
含广告、木马病毒资源
*投诉人姓名:
*投诉人联系方式:
*版权证明:
*详细原因:
C#三层架构代码生成器当前位置: >>
C#三层架构教程(含示例代码)
我寄愁心与明月,随风直到夜郎西。秋风吹不尽,总是玉关情。女娲炼石补天处,石破天惊逗秋雨。恸哭六军俱缟素,冲冠一怒为红颜。忠言逆耳利于行,良药苦口利于病。
本文由wmy24贡献
doc文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。
实体类的设计与实现...... 2 接口的设计与实现...... 10 依赖注入...... 27 数据访问实现方法一:ACCESS+SQL ...... 40 *方式一的重构...... 57 数据访问实现方式二:SQL SERVER+存储过程 ...... 78 数据访问的第三种实现:基于 Nbear 的 ORM 实现 ...... 102 业务逻辑层实现...... 117 表示层实现...... 124
实体类的设计与实现
实体类是现实实体在计算机中的表示。 它贯穿于整个架构, 负担着在各层次及模块间传递数 据的职责。一般来说,实体类可以分为&贫血实体类&和&充血实体类&,前者仅仅保存实体的 属性,而后者还包含一些实体间的关系与逻辑。我们在这个 Demo 中用的实体类将是&贫血 实体类&。 大多情况下, 实体类和数据库中的表 (这里指实体表, 不包括表示多对多对应的关系表) 是一一对应的,但这并不是一个限制,在复杂的数据库设计中,有可能出现一个实体类对应 多个表,或者交叉对应的情况。在本文的 Demo 中,实体类和表是一一对应的,并且实体 类中的属性和表中的字段也是对应的。 在看实体类的代码前,先看一下系统的工程结构。
如上图所示,在初始阶段,整个系统包括 6 个工程,它们的职责是这样的: Web--表示层 Entity--存放实体类 Factory--存放和依赖注入及 IoC 相关的类 IBLL--存放业务逻辑层接口族 IDAL--存放数据访问层接口族 Utility--存放各种工具类及辅助类
这只是一个初期架构,主要是将整个系统搭一个框架,在后续开发中,将会有其他工程 被陆陆续续添加进来。 我们的实体类将放在 Entity 工程下,这里包括三个文件:AdminInfo.cs,MessageInfo. cs,CommentInfo.cs,分别是管理员实体类、留言实体类和评论实体类。具体代码如下: AdminInfo.cs: AdminInfo
1using S 2 3namespace NGuestBook.Entity 4{ 5 6 /**////
/// 实体类-管理员
7 8 9 10 11 12 13 14 15 16
[Serializable] public class AdminInfo { pri
public int ID {
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33} 34 } } } }
get { return this. } set { this.id = }
public string Name { get { return this. } set { this.name = }
public string Password { get { return this. } set { this.password = }
MessageInfo.cs: MessageInfo
1using S 2 3namespace NGuestBook.Entity 4{ 5 6 /**////
/// 实体类-留言
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
[Serializable] public class MessageInfo { private string guestN private string guestE pr private DateT
private string isP
public int ID { get { return this. } set { this.id = }
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
public string GuestName { get { return this.guestN } set { this.guestName = } }
public string GuestEmail { get { return this.guestE } set { this.guestEmail = } }
public string Content { get { return this. } set { this.content = } }
public DateTime Time {
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61} 62 } } } }
get { return this. } set { this.time = }
public string Reply { get { return this. } set { this.reply = }
public string IsPass { get { return this.isP } set { this.isPass = }
CommentInfo.cs: CommentInfo
1using S 2 3namespace NGuestBook.Entity 4{ 5 6 /**////
/// 实体类-评论
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
[Serializable] public class CommentInfo { pr private DateT
public int ID { get { return this. } set { this.id = } }
public string Content
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40} 41 }
{ get { return this. } set { this.content = } }
public DateTime Time { get { return this. } set { this.time = } }
public int Message { get { return this. } set { this.message = } }
大家可以看出,实体类的代码很简单,仅仅是负责实体的表示和数据的传递,不包含任 何逻辑性内容。下篇将介绍接口的设计。
接口的设计与实现
接下来,将进行接口的设计。这里包括数据访问层接口和业务逻辑层接口。在分层架构中, 接口扮演着非常重要的角色, 它不但直接决定了各层中的各个操作类需要实现何种操作, 而 且它明确了各个层次的职责。接口也是系统实现依赖注入机制不可缺少的部分。 本项目的接口设计将按如下顺序进行: 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
1using S 2using System.Collections.G 3using System.T 4using NGuestBook.E 5 6namespace NGuestBook.IBLL 7{ 8 9 /**////
/// 业务逻辑层接口-管理员
10 11 12 13 14
public interface IAdminBLL { /**////
/// 添加管理员
新管理员实体类 /// &returns&是否成功&/returns&
18 19 20 21
bool Add(AdminInfo admin);
/// 删除管理员
欲删除的管理员的 ID /// &returns&是否成功&/returns&
25 26 27 28
bool Remove(int id);
/// 修改管理员密码
29 30 31 32
欲修改密码的管理员的 ID ///
新密码 /// &returns&是否成功&/returns&
33 34 35 36
bool ChangePassword(int id,string password);
/// 管理员登录
管理员登录名 ///
管理员密码
/// &returns&如果登录成功,则返回相应管理员的实体类,否则返回 null&/returns&
41 42 43 44
AdminInfo Login(string name,string password);
/// 取得全部管理员信息
/// &returns&管理员实体类集合&/returns&
47 48 49} }
IList GetAll();
IMessageBLL.cs: IMessageBLL
1using S 2using System.Collections.G 3using System.T 4using NGuestBook.E 5 6namespace NGuestBook.IBLL 7{ 8 9 /**////
/// 业务逻辑层接口-留言
10 11 12 13 14
public interface IMessageBLL { /**////
/// 添加留言
新留言实体类 /// &returns&是否成功&/returns&
18 19 20 21
bool Add(MessageInfo message);
/// 删除留言
欲删除的留言的 ID /// &returns&是否成功&/returns&
25 26 27 28
bool Remove(int id);
/// 回复留言
要回复的留言的 ID ///
/// &returns&是否成功&/returns&
33 34 35 36
bool Revert(int id, string reply);
/// 将留言通过验证
通过验证的留言的 ID /// &returns&是否成功&/returns&
40 41 42 43
bool Pass(int id);
/// 按分页取得留言信息
44 45 46 47
每页显示几条留言 ///
当前页码 /// &returns&留言实体类集合&/returns&
48 49 50} }
IList&MessageInfo& GetByPage(int pageSize,int pageNumber);
ICommentBLL.cs ICommentBLL
1using S 2using System.Collections.G 3using System.T 4using NGuestBook.E 5 6namespace NGuestBook.IBLL 7{ 8 9 /**////
/// 业务逻辑层接口-评论
10 11 12 13 14
public interface ICommentBLL { /**////
/// 添加评论
新评论实体类 /// &returns&是否成功&/returns&
18 19 20 21
bool Add(CommentInfo comment);
/// 删除评论
欲删除的评论的 ID /// &returns&是否成功&/returns&
25 26 27 28
bool Remove(int id);
/// 取得指定留言的全部评论
指定留言的 ID /// &returns&评论实体类集合&/returns&
32 33 34} }
IList&CommentInfo& GetByMessage(int messageId);
由业务逻辑确定数据访问操作 IAdminBLL 需要的数据访问操作:插入管理员,删除管理员,更新管理员信息,按 ID 取得管理员信息,按登录名与密码取得管理员,取得全部管理员 IMessageBLL 需要的数据访问操作:插入留言,删除留言,更新留言信息,按 ID 取得留言 信息,按分页取得留言 ICommentBLL 需要的数据访问操作:插入评论,删除评论,按留言取得全部评论 另外,添加管理员时需要验证是否存在同名管理员,所以需要添加一个&按登录名取得 管理员&。 对以上操作进行整理,的如下接口操作:
IAdminDAL:Insert,Delete,Update,GetByID,GetByNameAndPassword,GetAl l IMessageDAL:Insert,Delete,Update,GetByID,GetByPage ICommentDAL:Insert,Delete,GetByMessage 这三个接口文件放在 IDAL 工程下,具体代码如下: IAdminDAL.cs:
IAdminDAL 1using S
2using System.Collections.G 3using System.T 4using NGuestBook.E 5 6namespace NGuestBook.IDAL 7{ 8 9 /**////
/// 数据访问层接口-管理员
10 11 12 13 14
public interface IAdminDAL { /**////
/// 插入管理员
管理员实体类 /// &returns&是否成功&/returns&
18 19 20 21
bool Insert(AdminInfo admin);
/// 删除管理员
欲删除的管理员的 ID /// &returns&是否成功&/returns&
25 26 27 28
bool Delete(int id);
/// 更新管理员信息
管理员实体类 /// &returns&是否成功&/returns&
32 33 34 35
bool Update(AdminInfo admin);
/// 按 ID 取得管理员信息
/// &returns&管理员实体类&/returns&
39 40 41 42
AdminInfo GetByID(int id);
/// 按管理员名取得管理员信息
管理员名 /// &returns&管理员实体类&/returns&
46 47 48 49
AdminInfo GetByName(string name);
/// 按用户名及密码取得管理员信息
50 51 52 53
用户名 ///
密码 /// &returns&管理员实体类,不存在时返回 null&/returns&
54 55 56 57
AdminInfo GetByNameAndPassword(string name,string password);
/// 取得全部管理员信息
/// &returns&管理员实体类集合&/returns&
60 61 62} }
IList GetAll();
IMessageDAL.cs: IMessageDAL
1using S 2using System.Collections.G 3using System.T 4using NGuestBook.E 5 6namespace NGuestBook.IDAL 7{ 8 9 /**////
/// 数据访问层接口-留言
10 11 12 13 14
public interface IMessageDAL { /**////
/// 插入留言
留言实体类
/// &returns&是否成功&/returns&
18 19 20 21
bool Insert(MessageInfo message);
/// 删除留言
欲删除的留言的 ID /// &returns&是否成功&/returns&
25 26 27 28
bool Delete(int id);
/// 更新留言信息
留言实体类 /// &returns&是否成功&/returns&
32 33 34 35
bool Update(MessageInfo message);
/// 按 ID 取得留言信息
留言 ID /// &returns&留言实体类&/returns&
39 40 41 42
MessageInfo GetByID(int id);
/// 按分页取得留言信息
43 44 45 46
每页显示几条留言 ///
当前页码 /// &returns&留言实体类集合&/returns&
47 48 49} }
IList&MessageInfo& GetByPage(int pageSize,int pageNumber);
ICommentDAL.cs: ICommentDAL
1using S 2using System.Collections.G 3using System.T 4using NGuestBook.E 5 6namespace NGuestBook.IDAL 7{ 8 /**////
/// 数据访问层接口-评论
10 11 12 13 14
public interface ICommentDAL { /**////
/// 插入评论
评论实体类 /// &returns&是否成功&/returns&
18 19 20 21
bool Insert(CommentInfo comment);
/// 删除评论
欲删除的评论的 ID /// &returns&是否成功&/returns&
25 26 27 28
bool Delete(int id);
/// 取得指定留言的全部评论
指定留言的 ID
/// &returns&评论实体类集合&/returns&
32 33 34} }
IList&CommentInfo& GetByMessage(int messageId);
我们设计的分层架构,层与层之间应该是松散耦合的。因为是单向单一调用,所以,这里的 &松散耦合&实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口。这 样,上层类不能直接实例化下层中的类,而只持有接口,至于接口所指变量最终究竟是哪一 个类,则由依赖注入机制决定。 之所以这样做,是为了实现层与层之间的&可替换&式设计,例如,现在需要换一种方式 实现数据访问层, 只要这个实现遵循了前面定义的数据访问层接口, 业务逻辑层和表示层不 需要做任何改动,只需要改一下配置文件系统即可正常运行。另外,基于这种结构的系统, 还可以实现并行开发。即不同开发人员可以专注于自己的层次,只有接口被定义好了,开发 出来的东西就可以无缝连接。 在 J2EE 平台上,主要使用 Spring 框架实现依赖注入。这里,我们将自己做一个依赖 注入容器。 依赖注入的理论基础是 Abstract Factory 设计模式,这里结合具体实例简单介绍一下。
上图以数据访问层为例,展示了 Abstract Factory 模式的应用。如图,现假设有针对 A ccess 和 SQLServer 两种数据库的数据访问层,它们都实现了数据访问层接口。每个数据 访问层有自己的工厂,所有工厂都实现自 IDALFactory 接口。而客户类(这里就是业务逻 辑层类)仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样,只要通过配置文件 确定实例化哪个工厂,就可以得到不同的数据访问层。 然而,这种设计虽然可行,但是代码比较冗余,因为这样需要为数据访问层的每一个实 现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但是,.NET 平台引入的反 射机制,给我们提供了一种解决方案。使用反射,每个层只需要一个工厂,然后通过从配置 文件中读出程序集的名称,动态加载相应类。另外,为了提高依赖注入机制的效率,这里引 入缓存机制。下面来看具体实现。 配置 首先,需要在 Web 工程的 Web.config 文件的节点下添加如下两个项:
这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value 目前 是空,是因为目前还没有各个层次的具体实现。 实现缓存操作辅助类 为实现缓存操作,我们将缓存操作封装成一个辅助类,放在 Utility 工程下,具体代码如 下: CacheAccess.cs: CacheAccess
1using S 2using System.W 3using System.Web.C 4 5namespace NGuestBook.Utility 6{ 7 8 /**////
/// 辅助类,用于缓存操作
9 10 11 12 13
public sealed class CacheAccess { /**////
/// 将对象加入到缓存中
14 15 16 17
缓存键 ///
缓存对象 ///
缓存依赖项
public static void SaveToCache(string cacheKey, object cacheObject, Cach
eDependency dependency) 19 20 21 { Cache cache = HttpRuntime.C cache.Insert(cacheKey, cacheObject, dependency);
22 23 24 25
/// 从缓存中取得对象,不存在则返回 null
缓存键 /// &returns&获取的缓存对象&/returns&
29 30 31 32 33 34 35 36} }
public static object GetFromCache(string cacheKey) { Cache cache = HttpRuntime.C
return cache[cacheKey]; }
封装依赖注入代码 因为很多依赖注入代码非常相似, 为了减少重复性代码, 我们将可复用的代码先封装在 一个类中。具体代码如下(这个类放在 Factory 工程下): DependencyInjector.cs: DependencyInjector
1using S 2using System.C 3using System.R 4using System.W 5using System.Web.C 6using NGuestBook.U 7 8namespace NGuestBook.Factory 9{ 10 11 12 /**////
/// 依赖注入提供者 /// 使用反射机制实现
13 14 15 16 17 18
public sealed class DependencyInjector { /**////
/// 取得数据访问层对象 /// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
数据访问类名称 /// &returns&数据访问层对象&/returns&
public static object GetDALObject(string className)
23 24 25 26
/// 取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取 /// 缓存依赖项为 Web.Config 文件
27 28 29 30 31
object dal = CacheAccess.GetFromCache(&DAL&); if (dal == null) { CacheDependency fileDependency = new CacheDependency(HttpCo
ntext.Current.Server.MapPath(&Web.Config&)); 32 33 34 35 36 37 /**////
/// 取得数据访问层对象 } dal = ConfigurationManager.AppSettings[&DAL&]; CacheAccess.SaveToCache(&DAL&, dal, fileDependency);
38 39 40 41 42 43
string dalName = (string) string fullClassName = dalName + &.& + classN object dalObject = CacheAccess.GetFromCache(className); if (dalObject == null) {
CacheDependency fileDependency = new CacheDependency(HttpCo
ntext.Current.Server.MapPath(&Web.Config&)); 45 e); 46 47 48 49 50 51 52 53 54 /**////
/// 取得业务逻辑层对象 /// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象 } return dalO } CacheAccess.SaveToCache(className, dalObject, fileDependency); dalObject = Assembly.Load(dalName).CreateInstance(fullClassNam
业务逻辑类名称 /// &returns&业务逻辑层对象&/returns&
58 59 60 61 62
public static object GetBLLObject(string className) { /**////
/// 取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取 /// 缓存依赖项为 Web.Config 文件
64 65 66 67
object bll = CacheAccess.GetFromCache(&BLL&); if (bll == null) { CacheDependency fileDependency = new CacheDependency(HttpCo
ntext.Current.Server.MapPath(&Web.Config&)); 68 69 70 71 72 73 /**////
/// 取得业务逻辑层对象 } bll = ConfigurationManager.AppSettings[&BLL&]; CacheAccess.SaveToCache(&BLL&, bll, fileDependency);
74 75 76 77 78 79 80
string bllName = (string) string fullClassName = bllName + &.& + classN object bllObject = CacheAccess.GetFromCache(className); if (bllObject == null) { CacheDependency fileDependency = new CacheDependency(HttpCo
ntext.Current.Server.MapPath(&Web.Config&)); 81 82 83 } bllObject = Assembly.Load(bllName).CreateInstance(fullClassName); CacheAccess.SaveToCache(className, bllObject, fileDependency);
84 85 86 87 88} } } return bllO
实现工厂 下面使用两个辅助类,实现数据访问层工厂和业务逻辑层工厂。 DALFactory.cs DALFactory
1using S 2using NGuestBook.IDAL; 3 4namespace NGuestBook.Factory 5{ 6 7 8 /**////
/// 数据访问层工厂,用于获取相应的数据访问层对象 /// 使用 Abstract Factory 设计模式+Facace 设计模式+反射机制+缓存机制设计
9 10 11 12
public sealed class DALFactory { /**////
/// 获取管理员数据访问层对象
/// &returns&管理员数据访问层对象&/returns&
16 17 18 19 20 21 22
public static IAdminDAL CreateAdminDAL() { return (IAdminDAL)DependencyInjector.GetDALObject(&AdminDAL&); }
/// 获取留言数据访问层对象
/// &returns&留言数据访问层对象&/returns&
25 26 27 28 29 30 31
public static IMessageDAL CreateMessageDAL() { return (IMessageDAL)DependencyInjector.GetDALObject(&MessageDAL&); }
/// 获取评论数据访问层对象
/// &returns&评论数据访问层对象&/returns&
public static ICommentDAL CreateCommentDAL()
35 36 L&); 37 38 39} }
{ return (ICommentDAL)DependencyInjector.GetDALObject(&CommentDA
BLLFactory.cs BLLFactory
1using S 2using NGuestBook.IBLL; 3 4namespace NGuestBook.Factory 5{ 6 7 8 /**////
/// 业务逻辑层工厂,用于获取相应的业务逻辑层对象 /// 使用 Abstract Factory 设计模式+Facace 设计模式+反射机制+缓存机制设计
9 10 11 12 13
public sealed class BLLFactory { /**////
/// 获取管理员业务逻辑层对象
/// &returns&管理员业务逻辑层对象&/returns&
16 17 18 19 20 21 22
public static IAdminBLL CreateAdminBLL() { return (IAdminBLL)DependencyInjector.GetBLLObject(&AdminBLL&); }
/// 获取留言业务逻辑层对象
/// &returns&留言业务逻辑层对象&/returns&
25 26 27 28 29 30 31
public static IMessageBLL CreateMessageBLL() { return (IMessageBLL)DependencyInjector.GetBLLObject(&MessageBLL&); }
/// 获取评论业务逻辑层对象
/// &returns&评论业务逻辑层对象&/returns&
public static ICommentBLL CreateCommentBLL() {
36 &); 37 38 39} } }
return (ICommentBLL)DependencyInjector.GetBLLObject(&CommentBLL
数据访问实现方法一: 数据访问实现方法一:ACCESS+SQL 实现方法一
经过上面篇文章的介绍,整个系统的框架算是基本搭建完了,下面,我们要具体实现各个层 次。关于数据访问层的实现,我准备讨论三种实现方式,这一篇文章讨论第一种:Access +动态生成 SQL。 顾名思义,这种实现将使用 Access 作为后台数据库,而操作方式也是最基本的使用 S QL 命令。 在具体编写实现代码之前,我们需要做一些准备工作: 第一步,我们要将 Access 数据库搭建完成,具体做法如下。 在 Web 工程下新建一个文件夹, 命名为 AccessData, 并在其中新建一个 mdb 文件 (即 Access 数据库文件),按照前面介绍过的数据库设计构架,将数据表及表间关系建好,这 里不再赘述。 第二步,我们要进行一些配置。 打开 Web 工程下的 Web.config 文件,在其中的 appSettings 节点下,添加如下键值:
第一条为 Access 的连接字符串,第二条为 Access 数据库文件的路径,其中&~&表示网 站根目录。 第三步,新建一个工程。 我们要新建一个工程 AccessDAL,用来存放 Access 数据访问层的代码。 准备工作做完了,现在来实现具体的代码。
1.编写数据访问助手类 因为很多数据访问操作流程很相似,所以,这里将一些可复用的代码抽取出来,编写成 助手类,以此减少代码量,提高代码复用性。 这个助手类放在 AccessDAL 下,叫 AccessDALHelper,主要负责 Access 数据库的访 问。它包括三个方法: GetConnectionString:从配置文件中读取配置项,组合成连接字符串。 ExecuteSQLNonQuery:执行指定 SQL 语句,不返回任何值,一般用于 Insert,Delet e,Update 命令。 ExecuteSQLDataReader:执行 SQL 语句返回查询结果,一般用于 Select 命令。 具体代码如下: AccessDALHelper.cs: AccessDALHelper
1using S 2using System.W 3using System.Web.C 4using System.C 5using System.D 6using System.Data.OleDb; 7using NGuestBook.U 8 9namespace NGuestBook.AccessDAL
10{ 11 12 /**////
/// Access 数据库操作助手
13 14 15 16 17 18
public sealed class AccessDALHelper { /**////
/// 读取 Access 数据库的连接字符串 /// 首先从缓存里读取,如果不存在则到配置文件中读取,并放入缓存
/// &returns&Access 数据库的连接字符串&/returns&
21 22 23 24 25 ing(); 26 27 28 29 30
private static string GetConnectionString() { if (CacheAccess.GetFromCache(&AccessConnectionString&) != null) { return CacheAccess.GetFromCache(&AccessConnectionString&).ToStr
} else { string dbPath = ConfigurationManager.AppSettings[&AccessPath&]; string dbAbsolutePath = HttpContext.Current.Server.MapPath(dbPat
h); 31 string connectionString = ConfigurationManager.AppSettings[&Acces
sConnectionString&]; 32 33 CacheDependency fileDependency = new CacheDependency(HttpCo
ntext.Current.Server.MapPath(&Web.Config&)); 34 CacheAccess.SaveToCache(&AccessConnectionString&, connectionStr
ing.Replace(&{DBPath}&, dbAbsolutePath), fileDependency); 35 36 37 38 39 40 41 /**////
/// 执行 SQL 语句并且不返回任何值 } } return connectionString.Replace(&{DBPath}&, dbAbsolutePath);
所执行的 SQL 命令 ///
public static void ExecuteSQLNonQuery(string SQLCommand,OleDbParamet
er[] parameters) 46 47 { OleDbConnection connection = new OleDbConnection(GetConnectionStr
ing()); 48 nection); 49 50 51 52 53 54 55 56 57 58 59 60 61 /**////
/// 执行 SQL 语句并返回包含查询结果的 DataReader } connection.Open(); command.ExecuteNonQuery(); connection.Close(); } for (int i = 0; i & parameters.L i++) { command.Parameters.Add(parameters[i]); OleDbCommand command = new OleDbCommand(SQLCommand, con
所执行的 SQL 命令 ///
/// &returns&&/returns& public static OleDbDataReader ExecuteSQLDataReader(string SQLComman
d,OleDbParameter[] parameters)
67 68 ing()); 69 nection); 70 71 72 73 74 75 76 77 78 79 80 81 82 83} }
{ OleDbConnection connection = new OleDbConnection(GetConnectionStr
OleDbCommand command = new OleDbCommand(SQLCommand, con
for (int i = 0; i & parameters.L i++) { command.Parameters.Add(parameters[i]); }
connection.Open(); OleDbDataReader dataReader = command.ExecuteReader(); //connection.Close();
return dataR }
2.实现具体的数据访问操作类 因为前面已经定义了数据访问层接口,所以实现数据访问操作类就是很机械的工作了。 下面仅以 Admin 的数据访问操作类为例:
AdminDAL: AdminDAL
1using S 2using System.Collections.G 3using System.T 4using System.D 5using System.Data.OleDb; 6using NGuestBook.IDAL; 7using NGuestBook.E 8 9namespace NGuestBook.AccessDAL 10{ 11 12 13 14 public class AdminDAL : IAdminDAL { /**////
/// 插入管理员
管理员实体类 /// &returns&是否成功&/returns&
public bool Insert(AdminInfo admin) { string SQLCommand = &insert into [TAdmin]([Name],[Password]) valu
es(@name,@password)&; 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 /**////
/// 删除管理员 } } } catch { try { AccessDALHelper.ExecuteSQLNonQuery(SQLCommand, parameters); }; OleDbParameter[] parameters ={ new OleDbParameter(&name&,admin.Name), new OleDbParameter(&password&,admin.Password)
欲删除的管理员的 ID /// &returns&是否成功&/returns&
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
public bool Delete(int id) { string SQLCommand = &delete from [TAdmin] where [ID]=@id&; OleDbParameter[] parameters ={ new OleDbParameter(&id&,id) };
try { AccessDALHelper.ExecuteSQLNonQuery(SQLCommand, parameters); } catch { } }
/// 更新管理员信息
管理员实体类
/// &returns&是否成功&/returns&
public bool Update(AdminInfo admin) { string SQLCommand = &update [TAdmin] set [Name]=@name,[Passwo
rd]=@password where [ID]=@id&; 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 } } } catch { try { AccessDALHelper.ExecuteSQLNonQuery(SQLCommand, parameters); }; OleDbParameter[] parameters ={ new OleDbParameter(&id&,admin.ID), new OleDbParameter(&name&,admin.Name), new OleDbParameter(&password&,admin.Password)
/// 按 ID 取得管理员信息
管理员 ID /// &returns&管理员实体类&/returns&
90 91 92 93 94 95 96 97 98 99
public AdminInfo GetByID(int id) { string SQLCommand = &select * from [TAdmin] where [ID]=@id&; OleDbParameter[] parameters ={ new OleDbParameter(&id&,id) };
try { OleDbDataReader dataReader = AccessDALHelper.ExecuteSQLData
Reader(SQLCommand, parameters); 100 101 102 103 104 105 AdminInfo admin = new AdminInfo(); } if (!dataReader.HasRows) { throw new Exception();
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 } } }
dataReader.Read(); admin.ID=(int)dataReader[&ID&]; admin.Name=(string)dataReader[&Name&]; admin.Password=(string)dataReader[&Password&];
/// 按用户名及密码取得管理员信息
121 122 123 124
用户名 ///
密码 /// &returns&管理员实体类,不存在时返回 null&/returns&
125 126 127
public AdminInfo GetByNameAndPassword(string name, string password) { string SQLCommand = &select * from [TAdmin] where [Name]=@na
me and [Password]=@password&; 128 129 130 131 132 133 134 135 try { OleDbDataReader dataReader = AccessDALHelper.ExecuteSQLDat }; OleDbParameter[] parameters ={ new OleDbParameter(&name&,name), new OleDbParameter(&password&,password),
aReader(SQLCommand, parameters); 136 137 138 139 140 141 142 143 144 145 146 147 AdminInfo admin = new AdminInfo(); dataReader.Read(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; admin.Password = (string)dataReader[&Password&]; } if (!dataReader.HasRows) { throw new Exception();
148 149 150 151 152 153 154 155 156 }
} catch { }
/// 按管理员名取得管理员信息
157 158 159
管理员名 /// &returns&管理员实体类&/returns&
160 161 162 me&; 163 164 165 166 167 168
public AdminInfo GetByName(string name) { string SQLCommand = &select * from [TAdmin] where [Name]=@na
OleDbParameter[] parameters ={ new OleDbParameter(&name&,name), };
OleDbDataReader dataReader = AccessDALHelper.ExecuteSQLDat
aReader(SQLCommand, parameters); 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 /**////
} } } catch { AdminInfo admin = new AdminInfo(); dataReader.Read(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; admin.Password = (string)dataReader[&Password&]; } if (!dataReader.HasRows) { throw new Exception();
/// 取得全部管理员信息
/// &returns&管理员实体类集合&/returns&
193 194 195 196 197 198
public IList GetAll() { string SQLCommand = &select * from [TAdmin]&; try { OleDbDataReader dataReader = AccessDALHelper.ExecuteSQLDat
aReader(SQLCommand, null); 199 200 201 202 203 204 205 206 207 208 209 210 IList adminCollection = new List(); int i = 0; while (dataReader.Read()) { AdminInfo admin = new AdminInfo(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; } if (!dataReader.HasRows) { throw new Exception();
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225} } } } } catch { }
admin.Password = (string)dataReader[&Password&];
adminCollection.Add(admin); i++;
return adminC
可以看到,这里主要包括三种类型的操作,一种是修改型,如 Insert;一种是返回单个 实体类型,如 GetByID;还有一种是返回实体类集合型,如 GetAll。 MessageDAL 和 CommentDAL 的实现非常相似,在这里不再赘述。
*方式一的重构 方式一的重构 方式一的
昨天的文章基于.NET 平台的分层架构实战(七)--数据访问层的第一种实现:Access+ SQL 发布后,很多朋友对我的程序提出了意见和建议,在这里先谢谢你们!!!尤其是金 色海洋(jyk),对我的程序提出了很多建设性的意见。 我大体总结了一下,昨天程序的主要缺点有: 1.Connection 对象没有关闭 2.DataReader 对象没有关闭 3.相似代码太多,造成代码冗余。 其中第一点问题,目前还没有太好的解决方案,主要是因为 Connection 一旦关闭,Da taReader 就无法读取了。而且,Connection 对象应该会自动在适当的时候关闭(通过观察 临时文件得出),并且在实际运行时并无影响(在功能上),所以这里没有专门解决。而针 对后面两个问题,我使用了如下解决方案。 对于关闭 DataReader 的方法,实现起来很简单,在 finally 里将他关闭就行了。关键是 如何去处冗余代码。 经过我的分析,数据访问层的操作可以分为三类:不返回数据,返回单个实体类,返回 实体类集合。我将这三种操作的公共部分抽出,写成三个方法放在 AccessDALHelper 里, 类型不同的问题使用泛型解决。 这样做有一个难题,就是不同实体在由 DataReader 转化为实体类时的代码很不一样, 无法抽出。这里,我使用了 Strategy 模式解决。具体做法是:首先定义一个由 DataReade r 转换为实体类的策略接口,然后为不同的实体编写不同的转换策略,示意图如下:
可以看出,所有转换策略都要实现 IDataReaderToEntityStrategy 接口,并且每个策略 都有一个自组合,这是以为他们都要实现 Singleton 模式。而 AccessDALHelper 与具体策 略无关,仅与接口耦合。 下面来看一下具体代码: 首先是 IDataReaderToEntityStrategy 接口 IDataReaderToEntityStrategy.cs: IDataReaderToEntityStrategy
1using S 2using System.Collections.G 3using System.T 4using System.D 5using System.Data.OleDb; 6 7namespace NGuestBook.AccessDAL
8{ 9 10 /**////
/// 由 DataReader 转换成实体类的策略接口
11 12 13 14 15
public interface IDataReaderToEntityStrategy&T& { /**////
/// 将 DataReader 转换为实体类,采用泛型
包含数据的 DataReader 对象 /// &returns&实体类&/returns&
19 20 21} }
T DataReaderToEntity(OleDbDataReader dataReader);
然后以 Admin 为例,看一下策略的具体实现: AdminDataReaderToEntityStrategy.cs: AdminDataReaderToEntityStrategy
1using S 2using System.Collections.G 3using System.T 4using System.D
5using System.Data.OleDb; 6using NGuestBook.E 7 8namespace NGuestBook.AccessDAL 9{ 10 11 12 /**////
/// DataReader 到实体类的转换策略-管理员 /// 实现上使用 Singleton 模式,保证全局唯一实例
public class AdminDataReaderToEntityStrategy : IDataReaderToEntityStrategy
15 16 17 18 19 /**////
/// 私有化构造函数,保证无法外部实例化 { private static AdminDataReaderToEntityStrategy singleInstance =
20 21 22 23 24
private AdminDataReaderToEntityStrategy() { }
/// 静态方法,用于取得全局唯一实例
/// &returns&全局唯一实例&/returns&
27 28 29 30 31 32 33 34 35 36 37 38
public static AdminDataReaderToEntityStrategy GetInstance() { if (singleInstance == null) { singleInstance = new AdminDataReaderToEntityStrategy(); }
return singleI }
/// 由 DataReader 转换到管理员实体类
包含数据的 DataReader 对象 /// &returns&管理员实体类&/returns&
42 43 44 45 46 47
public AdminInfo DataReaderToEntity(OleDbDataReader dataReader) { AdminInfo admin = new AdminInfo(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; admin.Password = (string)dataReader[&Password&];
48 49 50 51 52} } }
可以看到,这里实现了一个单件模式。下一个,是重构后的 AccessDALHelper,增加了三 个方法。 AccessDALHelper.cs: AccessDALHelper
1using S 2using System.Collections.G 3using System.W 4using System.Web.C 5using System.C 6using System.D 7using System.Data.OleDb; 8using NGuestBook.U 9 10namespace NGuestBook.AccessDAL 11{ 12 /**////
/// Access 数据库操作助手
14 15 16 17 18 19
public sealed class AccessDALHelper { /**////
/// 读取 Access 数据库的连接字符串 /// 首先从缓存里读取,如果不存在则到配置文件中读取,并放入缓存
/// &returns&Access 数据库的连接字符串&/returns&
22 23 24 25 26 ing(); 27 28 29 30 31 h); 32
private static string GetConnectionString() { if (CacheAccess.GetFromCache(&AccessConnectionString&) != null) { return CacheAccess.GetFromCache(&AccessConnectionString&).ToStr
} else { string dbPath = ConfigurationManager.AppSettings[&AccessPath&]; string dbAbsolutePath = HttpContext.Current.Server.MapPath(dbPat
string connectionString = ConfigurationManager.AppSettings[&Acces
sConnectionString&]; 33 34 CacheDependency fileDependency = new CacheDependency(HttpCo
ntext.Current.Server.MapPath(&Web.Config&)); 35 CacheAccess.SaveToCache(&AccessConnectionString&, connectionStr
ing.Replace(&{DBPath}&, dbAbsolutePath), fileDependency); 36 37 38 39 40 41 42 /**////
/// 执行 SQL 语句并且不返回任何值 } } return connectionString.Replace(&{DBPath}&, dbAbsolutePath);
所执行的 SQL 命令 ///
public static void ExecuteSQLNonQuery(string SQLCommand, OleDbParam
eter[] parameters) 47 48 ing()); 49 OleDbCommand command = new OleDbCommand(SQLCommand, con { OleDbConnection connection = new OleDbConnection(GetConnectionStr
nection); 50 51 52 53 54 55 56 57 58 59 60 61 62 /**////
/// 执行 SQL 语句并返回包含查询结果的 DataReader } connection.Open(); command.ExecuteNonQuery(); connection.Close(); } for (int i = 0; i & parameters.L i++) { command.Parameters.Add(parameters[i]);
所执行的 SQL 命令 ///
/// &returns&&/returns& public static OleDbDataReader ExecuteSQLDataReader(string SQLComman
d, OleDbParameter[] parameters) 68 69 { OleDbConnection connection = new OleDbConnection(GetConnectionStr
ing()); 70 nection); 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 /**////
/// 执行不需要返回数据的操作 } return dataR connection.Open(); OleDbDataReader dataReader = command.ExecuteReader(); //connection.Close(); } for (int i = 0; i & parameters.L i++) { command.Parameters.Add(parameters[i]); OleDbCommand command = new OleDbCommand(SQLCommand, con
86 87 88 89
SQL 命令 ///
参数 /// &returns&是否成功&/returns&
public static bool OperateNonData(string SQLCommand, OleDbParameter[]
parameters) 91 92 93 94 95 96 97 98 99 100 101 102 103 104 /**////
/// 执行返回单个实体类的操作 } } } catch { { try { ExecuteSQLNonQuery(SQLCommand, parameters);
105 106 107 108 109 110
/// &typeparam name=&T&&实体类类型&/typeparam& ///
SQL 命令 ///
DataReader 到实体类的转换策略 /// &returns&实体类&/returns&
public static T OperateEntity&T&(string SQLCommand, OleDbParameter[]
parameters, IDataReaderToEntityStrategy&T& strategy) 112 113 { OleDbDataReader dataReader = ExecuteSQLDataReader(SQLComman
d, parameters); 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 } finally { dataReader.Close(); } catch { return default(T); dataReader.Read(); return strategy.DataReaderToEntity(dataReader); } try { if (!dataReader.HasRows) { throw new Exception();
131 132 133 134 135 }
/// 执行返回实体类集合的操作
136 137 138 139 140 141
/// &typeparam name=&T&&实体类类型&/typeparam& ///
SQL 命令 ///
DataReader 到实体类的转换策略 /// &returns&实体类&/returns&
public static IList&T& OperateEntityCollection&T&(string SQLCommand, O
leDbParameter[] parameters, IDataReaderToEntityStrategy&T& strategy) 143 144 { OleDbDataReader dataReader = AccessDALHelper.ExecuteSQLDataRea
der(SQLCommand, null); 145 146 147 148 149 150 } try { if (!dataReader.HasRows) { throw new Exception();
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172} } } } } finally { dataReader.Close(); } catch { return default(IList&T&); return entityC } IList&T& entityCollection = new List&T&(); int i = 0; while (dataReader.Read()) { entityCollection.Add(strategy.DataReaderToEntity(dataReader)); i++;
最后以 Admin 为例,看一下简化后的数据访问层实现: AdminDAL.cs:
2using System.Collections.G 3using System.T 4using System.D 5using System.Data.OleDb; 6using NGuestBook.IDAL; 7using NGuestBook.E 8 9namespace NGuestBook.AccessDAL 10{ 11 12 13 14 public class AdminDAL : IAdminDAL { /**////
/// 插入管理员
管理员实体类 /// &returns&是否成功&/returns&
public bool Insert(AdminInfo admin) { string SQLCommand = &insert into [TAdmin]([Name],[Password]) valu
es(@name,@password)&; 21 22 23 24 25 26 27 28 29 30 31 32 /**////
/// 删除管理员 } return AccessDALHelper.OperateNonData(SQLCommand, parameters); }; parameters[0].Value = admin.N parameters[1].Value = admin.P OleDbParameter[] parameters ={ new OleDbParameter(&name&,OleDbType.VarChar,20), new OleDbParameter(&password&,OleDbType.VarChar,50)
欲删除的管理员的 ID /// &returns&是否成功&/returns&
36 37 38 39 40 41
public bool Delete(int id) { string SQLCommand = &delete from [TAdmin] where [ID]=@id&; OleDbParameter[] parameters ={ new OleDbParameter(&id&,OleDbType.Integer) };
42 43 44 45 46 47 48 }
parameters[0].Value =
return AccessDALHelper.OperateNonData(SQLCommand, parameters);
/// 更新管理员信息
管理员实体类 /// &returns&是否成功&/returns&
public bool Update(AdminInfo admin) { string SQLCommand = &update [TAdmin] set [Name]=@name,[Passwo
rd]=@password where [ID]=@id&; 55 56 57 58 59 60 61 62 }; parameters[0].Value = admin.ID; parameters[1].Value = admin.N parameters[2].Value = admin.P OleDbParameter[] parameters ={ new OleDbParameter(&id&,OleDbType.Integer), new OleDbParameter(&name&,OleDbType.VarChar,20), new OleDbParameter(&password&,OleDbType.VarChar,50)
63 64 65 66 67 68 /**////
/// 按 ID 取得管理员信息 } return AccessDALHelper.OperateNonData(SQLCommand, parameters);
管理员 ID /// &returns&管理员实体类&/returns&
72 73 74 75 76 77 78 79 80
public AdminInfo GetByID(int id) { string SQLCommand = &select * from [TAdmin] where [ID]=@id&; OleDbParameter[] parameters ={ new OleDbParameter(&id&,OleDbType.Integer) }; parameters[0].Value =
return AccessDALHelper.OperateEntity(SQLCommand, par
ameters, AdminDataReaderToEntityStrategy.GetInstance()); 81 82 83 /**////
/// 按用户名及密码取得管理员信息
85 86 87 88
用户名 ///
密码 /// &returns&管理员实体类,不存在时返回 null&/returns&
public AdminInfo GetByNameAndPassword(string name, string password) { string SQLCommand = &select * from [TAdmin] where [Name]=@nam
e and [Password]=@password&; 92 93 94 95 96 97 98 99 return AccessDALHelper.OperateEntity(SQLCommand, par }; parameters[0].Value = parameters[1].Value = OleDbParameter[] parameters ={ new OleDbParameter(&name&,OleDbType.VarChar,20), new OleDbParameter(&password&,OleDbType.VarChar,50)
ameters, AdminDataReaderToEntityStrategy.GetInstance()); 100 101 102 103 /**////
/// 按管理员名取得管理员信息 }
104 105 106
管理员名 /// &returns&管理员实体类&/returns&
107 108 109 me&; 110 111 112 113 114 115
public AdminInfo GetByName(string name) { string SQLCommand = &select * from [TAdmin] where [Name]=@na
OleDbParameter[] parameters ={ new OleDbParameter(&name&,OleDbType.VarChar,20) }; parameters[0].Value =
return AccessDALHelper.OperateEntity(SQLCommand, pa
rameters, AdminDataReaderToEntityStrategy.GetInstance()); 116 117 118 119 /**////
/// 取得全部管理员信息 }
/// &returns&管理员实体类集合&/returns&
public IList GetAll() {
124 125 126
string SQLCommand = &select * from [TAdmin]&;
return AccessDALHelper.OperateEntityCollection(SQLCom
mand, null, AdminDataReaderToEntityStrategy.GetInstance()); 127 128 129} } }
数据访问实现方式二: 数据访问实现方式二:SQL SERVER+存储过程 存储过程
在上一篇中,讨论了使用 SQL 构建数据访问层的方法,并且针对的是 Access 数据库。而 这一篇中,将要创建一个针对 SQLServer 数据库的数据访问层,并且配合存储过程实现。 曾经有朋友问我使用 SQL 和存储过程在效率上的差别, 惭愧的是我对这方面没有研究, 也没有实际做过测试。通过查阅资料,发现在一般情况下,存储过程的效率由于使用 SQL, 但是也不绝对,也发现有的朋友测试时发现在特定情况下 SQL 的效率优于存储过程,所以 这个问题不能一概而论。 好,废话不多说,这里先列出使用存储过程构建数据访问层的一般步骤:
1.创建新工程 2.创建数据库 3.编写相应存储过程 4.编写数据库辅助类 5.实现数据访问层 创建新工程 在开始所有开发工作前,我们需要在解决方案下新建一个工程,叫 SQLServerDAL, 用于存放所有 SQLServer 数据访问层的代码。 创建数据库 首先,我们要根据前文设计的数据库,在 SQLServer 中创建相应的数据库及数据表。 我使用的是 SQLServer2005,使用企业管理器创建,创建方法不再赘述。 编写存储过程
数据库创建完成后,我们就要编写存储过程了。由于数据访问层接口已经确定,所以需 要哪些存储过程也很好确定。 例如数据访问层接口中有一个添加管理员方法, 那么就一定有 一个存储过程实现这个功能。 还是以管理员模块为例,经过简单分析,需要一下存储过程: 插入管理员记录 删除管理员记录 更新管理员信息 按 ID 取得管理员记录 按用户名及密码取得管理员记录 按用户名取得管理员记录 取得全部管理员记录 创建这些存储过程的 SQL 代码如下: 插入管理员记录
set ANSI_NULLS ON set QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: &T2 噬菌体&
-- Create date: && -- Description: &插入管理员记录&
-- =============================================
CREATE PROCEDURE [dbo].[Pr_InsertAdmin] ( @Name Nvarchar(20), @Password Nvarchar(50) ) AS INSERT INTO TAdmin ( [Name], [Password] ) VALUES ( @Name, @Password )
删除管理员记录
1set ANSI_NULLS ON 2set QUOTED_IDENTIFIER ON 3GO 4-- =============================================
5-- Author:
&T2 噬菌体&
6-- Create date: && 7-- Description: &删除管理员记录&
8-- ============================================= 9CREATE PROCEDURE [dbo].[Pr_DeleteAdmin] 10( 11 12) 13AS 14DELETE FROM TAdmin 15WHERE [ID]=@ID @ID Int
修改管理员信息
1set ANSI_NULLS ON 2set QUOTED_IDENTIFIER ON 3GO 4-- ============================================= 5-- Author: &T2 噬菌体&
6-- Create date: && 7-- Description: &修改管理员记录&
8-- ============================================= 9CREATE PROCEDURE [dbo].[Pr_UpdateAdmin]
10( 11 12 13 14) 15AS 16UPDATE TAdmin 17SET 18[Name]=@Name, 19[Password]=@Password 20WHERE [ID]=@ID @ID Int, @Name Nvarchar(20), @Password Nvarchar(50)
按 ID 取得管理员
1set ANSI_NULLS ON 2set QUOTED_IDENTIFIER ON 3GO 4-- ============================================= 5-- Author: &T2 噬菌体&
6-- Create date: && 7-- Description: &按 ID 取得管理员信息&
8-- ============================================= 9CREATE PROCEDURE [dbo].[Pr_GetAdminByID]
10( 11 12) 13AS 14SELECT * FROM TAdmin 15WHERE [ID]=@ID @ID Int
按用户名和密码取得管理员
1set ANSI_NULLS ON 2set QUOTED_IDENTIFIER ON 3GO 4-- ============================================= 5-- Author: &T2 噬菌体&
6-- Create date: && 7-- Description: &按用户名及密码取得管理员信息&
8-- ============================================= 9CREATE PROCEDURE [dbo].[Pr_GetAdminByNameAndPassword] 10( 11 12 13) 14AS @Name Nvarchar(20), @Password Nvarchar(50)
15SELECT * FROM TAdmin 16WHERE [Name]=@Name 17AND [Password]=@Password
按用户名取得管理员
1set ANSI_NULLS ON 2set QUOTED_IDENTIFIER ON 3GO 4-- ============================================= 5-- Author: &T2 噬菌体&
6-- Create date: && 7-- Description: &按用户名取得管理员信息&
8-- ============================================= 9CREATE PROCEDURE [dbo].[Pr_GetAdminByName] 10( 11 12) 13AS 14SELECT * FROM TAdmin 15WHERE [Name]=@Name @Name Nvarchar(20)
取得全部管理员信息
1set ANSI_NULLS ON 2set QUOTED_IDENTIFIER ON 3GO 4-- ============================================= 5-- Author: &T2 噬菌体&
6-- Create date: && 7-- Description: &取得全部管理员信息&
8-- ============================================= 9CREATE PROCEDURE [dbo].[Pr_GetAllAdmin] 10AS 11SELECT * FROM TAdmin
编写数据库辅助类 由于访问数据库的代码很相似, 这里我们仍需要编写一个数据库辅助类, 来将常用代码 封装起来,方便复用。虽然在这里只使用到了存储过程,但是为了扩展性考虑,这个数据库 辅助类仍然包含了通过 SQL 访问数据库的方法。具体实现如下: SQLServerDALHelper.cs: SQLServerDALHelper
1using S 2using System.Collections.G 3using System.C 4using System.D
5using System.Data.SqlC 6 7namespace NGuestBook.SQLServerDAL 8{ 9 10 /**////
/// SQLServer 数据库操作助手
11 12 13 14 15
public sealed class SQLServerDALHelper { /**////
/// 用于连接 SQLServer 数据库的连接字符串,存于 Web.config 中
private static readonly string _sqlConnectionString = ConfigurationManage
r.AppSettings[&SQLServerConnectionString&]; 18 19 20 /**////
/// 执行 SQL 命令,不返回任何值
public static void ExecuteSQLNonQurey(string sql) { SqlConnection connection = new SqlConnection(_sqlConnectionString);
26 27 28 29 30 31 32 33 }
SqlCommand command = new SqlCommand(sql,connection); connection.Open(); command.ExecuteNonQuery(); connection.Close();
/// 执行 SQL 命令,并返回 SqlDataReader
SQL 命令 /// &returns&包含查询结果的 SqlDataReader&/returns&
37 38 39 40 41 42 43 44 45 46 47
public static SqlDataReader ExecuteSQLReader(string sql) { SqlConnection connection = new SqlConnection(_sqlConnectionString); SqlCommand command = new SqlCommand(sql, connection); connection.Open(); SqlDataReader sqlReader = command.ExecuteReader(); //connection.Close();
return sqlR }
/// 执行存储过程,不返回任何值
存储过程名 ///
public static void ExecuteProcedureNonQurey(string storedProcedureName,
IDataParameter[] parameters) 54 55 56 nection); 57 58 59 60 61 62 63 64 65 66 67 } connection.Open(); command.ExecuteNonQuery(); connection.Close(); } command.CommandType = CommandType.StoredP if (parameters != null) { foreach (SqlParameter parameter in parameters) { command.Parameters.Add(parameter); { SqlConnection connection = new SqlConnection(_sqlConnectionString); SqlCommand command = new SqlCommand(storedProcedureName,con
68 69 70 71
/// 执行存储,并返回 SqlDataReader
72 73 74 75
存储过程名 ///
参数 /// &returns&包含查询结果的 SqlDataReader&/returns&
public static SqlDataReader ExecuteProcedureReader(string storedProcedur
eName,IDataParameter[] parameters) 77 78 79 nection); 80 81 82 83 84 85 86 87 } } command.CommandType = CommandType.StoredP if (parameters != null) { foreach (SqlParameter parameter in parameters) { command.Parameters.Add(parameter); { SqlConnection connection = new SqlConnection(_sqlConnectionString); SqlCommand command = new SqlCommand(storedProcedureName,con
88 89 90 91 92 93 94 95} } }
connection.Open(); SqlDataReader sqlReader = command.ExecuteReader(); //connection.Close();
return sqlR
实现数据访问层 最后仍以管理员模块为例,看一下具体数据访问层的实现。 AdminDAL.cs: AdminDAL
1using S 2using System.Collections.G 3using System.T 4using System.D 5using System.Data.SqlC 6using NGuestBook.IDAL; 7using NGuestBook.E 8 9namespace NGuestBook.SQLServerDAL
10{ 11 12 13 14 public class AdminDAL : IAdminDAL { /**////
/// 插入管理员
管理员实体类 /// &returns&是否成功&/returns&
18 19 20 21 22 23 24 25 26 27 28 29
public bool Insert(AdminInfo admin) { SqlParameter[] parameters = { new SqlParameter(&@Name&,SqlDbType.NVarChar), new SqlParameter(&@Password&,SqlDbType.NVarChar) }; parameters[0].Value = admin.N parameters[1].Value = admin.P try { SQLServerDALHelper.ExecuteProcedureNonQurey(&Pr_InsertAdmin&,
parameters); 30
31 32 33 34 35 36 37 38 39 }
} catch { }
/// 删除管理员
欲删除的管理员的 ID /// &returns&是否成功&/returns&
43 44 45 46 47 48 49 50 51 52
public bool Delete(int id) { SqlParameter[] parameters = { new SqlParameter(&@ID&,SqlDbType.Int) }; parameters[0].Value = try { SQLServerDALHelper.ExecuteProcedureNonQurey(&Pr_DeleteAdmin&,
parameters); 53 54 55 56 57 58 59 60 61 62 /**////
/// 更新管理员信息 } } } catch {
管理员实体类 /// &returns&是否成功&/returns&
66 67 68 69 70 71 72 73
public bool Update(AdminInfo admin) { SqlParameter[] parameters = { new SqlParameter(&@ID&,SqlDbType.Int), new SqlParameter(&@Name&,SqlDbType.NVarChar), new SqlParameter(&@Password&,SqlDbType.NVarChar) };
74 75 76 77 78 79 parameters); 80 81 82 83 84 85 86 87 88 89 }
parameters[0].Value = admin.ID; parameters[1].Value = admin.N parameters[2].Value = admin.P try { SQLServerDALHelper.ExecuteProcedureNonQurey(&Pr_UpdateAdmin&,
} catch { }
/// 按 ID 取得管理员信息
管理员 ID /// &returns&管理员实体类&/returns&
public AdminInfo GetByID(int id) {
95 96 97 98 99 100 101 102 103
SqlParameter[] parameters = { new SqlParameter(&@ID&,SqlDbType.Int) }; parameters[0].Value = SqlDataReader dataReader = try { dataReader = SQLServerDALHelper.ExecuteProcedureReader(&Get
AdminByID&, parameters); 104 105 106 107 108 109 110 111 112 113 114 115 } } catch { dataReader.Read(); AdminInfo admin = new AdminInfo(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; admin.Password = (string)dataReader[&Password&];
116 117 118 119 120 121 122 123 }
finally { dataReader.Close(); }
/// 按用户名及密码取得管理员信息
124 125 126 127
用户名 ///
密码 /// &returns&管理员实体类,不存在时返回 null&/returns&
128 129 130 131 132 133 134 135 136 137
public AdminInfo GetByNameAndPassword(string name, string password) { SqlParameter[] parameters = { new SqlParameter(&@Name&,SqlDbType.NVarChar), new SqlParameter(&@Password&,SqlDbType.NVarChar) }; parameters[0].Value = parameters[1].Value = SqlDataReader dataReader =
138 139 140
try { dataReader = SQLServerDALHelper.ExecuteProcedureReader(&Get
AdminByNameAndPassword&, parameters); 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 } } } finally { dataReader.Close(); } catch { dataReader.Read(); AdminInfo admin = new AdminInfo(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; admin.Password = (string)dataReader[&Password&];
/// 按管理员名取得管理员信息
161 162 163
管理员名 /// &returns&管理员实体类&/returns&
164 165 166 167 168 169 170 171 172 173 174
public AdminInfo GetByName(string name) { SqlParameter[] parameters = { new SqlParameter(&@Name&,SqlDbType.NVarChar) }; parameters[0].Value = SqlDataReader dataReader = try { dataReader = SQLServerDALHelper.ExecuteProcedureReader(&Get
AdminByName&, parameters); 175 176 177 178 179 dataReader.Read(); AdminInfo admin = new AdminInfo(); admin.ID = (int)dataReader[&ID&]; admin.Name = (string)dataReader[&Name&]; admin.Password = (string)dataReader[&Password&];
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 /**////
/// 取得全部管理员信息 } } } finally { dataReader.Close(); } catch {
/// &returns&管理员实体类集合&/returns&
197 198 199 200 201
public IList GetAll() { SqlDataReader dataReader = try {
202 AllAdmin&, null); 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 } } }
dataReader = SQLServerDALHelper.ExecuteProcedureReader(&Get
IList adminCollection=new List(); 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); }
return adminC
finally { dataReader.Close();
223 224 225} }
数据访问的第三种实现: 数据访问的第三种实现:基于 Nbear 的 ORM 实现
前面的文章讨论了使用 SQL 语句和存储过程两种数据访问层的实现方式,这一篇里,将讨 论使用 ORM 方式实现数据访问层的方法。 对象-关系映射(Object/Relation Mapping,简称 ORM),是随着面向对象的软件开 发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法, 关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。 对象和关系数据是业务 实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中 的对象之间存在关联和继承关系, 而在数据库中, 关系数据无法直接表达多对多关联和继承 关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关 系数据库数据的映射。 目前.NET 平台上有许多 ORM 框架可供选择,如 NBear、NHibernate 等等。这里我们 选择 NBear 实现 ORM。 NBear 是由博客园的 Teddy's Knowledge Base 团队开发的一个开源框架,主要用来 提高.NET 平台的开发效率,其中包含了 ORM、IoC、MVP 等多个组件,这里仅仅用到其 中的 ORM 功能。关于 NBear 的详细使用方法本文不再详述,请参考 NBear 入门教程。NB ear 的最新版本下载地址为 http://files.cnblogs.com/hjf1223/NBearV3.7.2.11_src.rar。 下面我们一步一步实现数据访问层的 ORM 实现。 1.创建实体设计工程 使用 NBear 实现 ORM 功能,首先要创建一个实体设计工程,这个工程最终不会应用 到系统中,但是必须通过它来生成 NBear 实体类以及配置文件。 首先,我们在解决方案下新建一个工程,名字为 NBearEntityDesign,并为这个工程添 加到文件 NBear.Common.Design.dll 的引用,这个文件在 NBear 文件包的 dist 目录下。 完成后,在这个工程下新建一个 C#文件,名为 EntityDesign.cs,这个文件就是设计文 件,根据对实体和数据库的设计,编写完整代码如下:
EntityDesign.cs
1using S 2using System.Collections.G 3using System.T 4using NBear.Common.D 5 6namespace NGuestBook.NBearEntityDesign 7{ 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public interface TComment : Entity { [PrimaryKey] int ID { } } public interface TAdmin : Entity { [PrimaryKey] int ID { } [SqlType(&nvarchar(20)&)] string Name { } [SqlType(&nvarchar(50)&)] string Password { }
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 }
[SqlType(&ntext&)] string Content { } DateTime Time { } int MessageID { }
public interface TMessage : Entity { [PrimaryKey] int ID { } [SqlType(&nvarchar(20)&)] string GuestName { } [SqlType(&nvarchar(100)&)] string GuestEmail { } [SqlType(&ntext&)] string Content { } DateTime Time { } [SqlType(&ntext&)] string Reply { } [SqlType(&nvarchar(10)&)] string IsPass { }
设计完后,将这个工程编译备用。 2.创建 NBear 专用实体类及配置文件 在 NBear 文件包的 dist 目录下,有一个 NBear.Tools.EntityDesignToEntity.exe 程序, 打开它,点击&Browse&按钮,选择刚才编译生成的 NGuestBook.NBearEntityDesign.dll 文 件,并在 Output Namespace 文本框里输入相应的命名空间,这里我们应输入&NGuestBo ok.NBearDAL&。然后点击&Generate Entities&按钮,这时会在底下的文本框里生成 NBear 专用实体类代码。 在解决方案下新建一个工程 NBearDAL,用于存放所有 ORM 数据访问层的实现代码。 在这个工程下新建 Entities.cs,将刚才自动生成的代码覆盖掉这个文件的代码,专用实体类 就做好了。 另外,需要给工程 NBearDAL 添加到 NBear.Common.dll 和 NBear.Data.dll 的引用, 这两个文件都在 dist 目录下。 点击&Generate Configuration&按钮,这时会生成配置代码。在 Web 工程下新建文件 N BearConfig.xml,将生成的代码复制到这个文件里保存。 最后还要修改一下 Web.config 文件。增加如下配置代码:
&configSections&
&/configSections& &entityConfig&
&/entityConfig&
然后再在&connectionStrings&节点下增加如下项:
其中 connectionString 是连接字符串,根据个人不同情况进行修改。这里使用的是 SQ LServer2005。 因为数据库在上一篇中已经创建好了,这里就不需要创建数据库了。 3.编写转换器 这里出现了一个矛盾:业务逻辑层和表示层需要使用通用的实体类,如 AdminInfo,而 NBear 需要使用专用实体类。怎么解决这个矛盾呢?我这里使用的方法是一个我称之为&转 换器&的方法。 即为没一个实体写一个专门的转换器,实现两种实体类的转换。这里以管理 员实体为例,这个转换器写在 NBearDAL 工程下的 AdminConvertor.cs 文件中。具体代码 如下: AdminConvertor
1using S 2using NGuestBook.E 3
4namespace NGuestBook.NBearDAL 5{ 6 7 /**////
/// 实体类转换器-管理员
8 9 10 11 12
public sealed class AdminConvertor { /**////
/// 由普通管理员实体类转化为 NBear 专用管理员实体类
普通实体类 /// &returns&NBear 专用实体类&/returns&
16 y) 17 18 19 20 21 22 23 24
public static TAdmin CommonEntityToNBearEntity(AdminInfo commonEntit
{ TAdmin nbaerEntity = new TAdmin(); nbaerEntity.ID = commonEntity.ID; nbaerEntity.Name = commonEntity.N nbaerEntity.Password = commonEntity.P
return nbaerE }
25 26 27 /**////
/// 由 NBear 专用管理员实体类转化为普通管理员实体类
NBear 专用实体类 /// &returns&普通实体类&/returns&
31 32 33 34 35 36 37 38 39 40 41} }
public static AdminInfo NBearEntityToCommonEntity(TAdmin nbearEntity) { AdminInfo commonEntity = new AdminInfo(); commonEntity.ID = nbearEntity.ID; commonEntity.Name = nbearEntity.N commonEntity.Password = nbearEntity.P
return commonE }
4.实现数据访问层 做完上述工作,我们就可以来实现数据访问层了。借助于 NBear 框架的支持,我们可 以非常方便的使用 ORM 方式访问数据库。关于 NBear 的细节,这里不再赘述,以管理员 为例,具体代码如下: AdminDAL.cs
1using S 2using System.Collections.G 3using System.T 4using System.Data.C 5using NGuestBook.IDAL; 6using NGuestBook.E 7using NBear.C 8using NBear.D 9 10namespace NGuestBook.NBearDAL 11{ 12 13 14 15 public class AdminDAL : IAdminDAL { /**////
/// 插入管理员
管理员实体类 /// &returns&是否成功&/returns&
19 20 21 22
public bool Insert(AdminInfo admin) { Gateway.SetDefaultDatabase(&NBearConnectionString&); DbTransaction transcation = Gateway.Default.BeginTransaction();
try { Gateway.Default.Save&TAdmin&(AdminConvertor.CommonEntityTo
NBearEntity(admin)); 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 /**////
/// 删除管理员 } } } finally { Gateway.Default.CloseTransaction(transcation); } catch { transcation.Rollback(); transcation.Commit();
欲删除的管理员的 ID
/// &returns&是否成功&/returns&
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
public bool Delete(int id) { Gateway.SetDefaultDatabase(&NBearConnectionString&); DbTransaction transcation = Gateway.Default.BeginTransaction(); try { Gateway.Default.Delete&TAdmin&(id); transcation.Commit(); } catch { transcation.Rollback(); } finally { Gateway.Default.CloseTransaction(transcation); } }
/// 更新管理员信息
管理员实体类 /// &returns&是否成功&/returns&
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 tion); 86
public bool Update(AdminInfo admin) { Gateway.SetDefaultDatabase(&NBearConnectionString&); DbTransaction transcation = Gateway.Default.BeginTransaction(); PropertyItem[] properties = { new PropertyItem(&Name&), new PropertyItem(&Password&) }; object[] values ={ admin.Name, admin.Password }; try { Gateway.Default.Update&TAdmin&(properties, values, null, transca
transcation.Commit();
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 } } } }
catch { transcation.Rollback();
finally { Gateway.Default.CloseTransaction(transcation);
/// 按 ID 取得管理员信息
102 103 104
管理员 ID /// &returns&管理员实体类&/returns&
105 106 107 108
public AdminInfo GetByID(int id) { Gateway.SetDefaultDatabase(&NBearConnectionString&); TAdmin tAdmin = Gateway.Default.Find&TAdmin&(TAdmin._.ID == i
d); 109 return tAdmin == null ? null : AdminConvertor.NBearEntityToCommo
nEntity(tAdmin); 110 111 112 113 /**////
/// 按用户名及密码取得管理员信息 }
114 115 116 117
用户名 ///
密码 /// &returns&管理员实体类,不存在时返回 null&/returns&
118 119 120 121
public AdminInfo GetByNameAndPassword(string name, string password) { Gateway.SetDefaultDatabase(&NBearConnectionString&); TAdmin tAdmin = Gateway.Default.Find&TAdmin&(TAdmin._.Name =
= name && TAdmin._.Password == password); 122 return tAdmin == null ? null : AdminConvertor.NBearEntityToCommo
nEntity(tAdmin); 123 124 125 126 /**////
/// 按管理员名取得管理员信息 }
127 128 129
管理员名 /// &returns&管理员实体类&/returns&
130 131 132 133 = name); 134
public AdminInfo GetByName(string name) { Gateway.SetDefaultDatabase(&NBearConnectionString&); TAdmin tAdmin = Gateway.Default.Find&TAdmin&(TAdmin._.Name =
return tAdmin == null ? null : AdminConvertor.NBearEntityToCommo
nEntity(tAdmin); 135 136 137 138 /**////
/// 取得全部管理员信息 }
/// &returns&管理员实体类集合&/returns&
141 142 143 144 145
public IList GetAll() { IList adminCollection = new List(); Gateway.SetDefaultDatabase(&NBearConnectionString&); TAdmin[] tAdminCollection = Gateway.Default.FindArray&TAdmin&(nu
ll, TAdmin._.ID.Desc);
146 147 148 (tAdmin)); 149 150 151 152 153} } }
foreach (TAdmin tAdmin in tAdminCollection) { adminCollection.Add(AdminConvertor.NBearEntityToCommonEntity
} return adminC
业务逻辑层实现
在这一篇文章中,将实现一个 NGuestBook 的业务逻辑层。 在实际应用中,业务逻辑层是至关重要的,他承载着整个系统最核心的部分,也是客户 最关注的部分。这一部分的实现,通常需要技术专家和领域专家通力合作。当然,在本文章 系列的 Demo 中,由于业务逻辑的简单性,这里看的可能还不是很明显。 在本篇文章的业务逻辑层实现中,业务逻辑层主要承担了以下职责:
1.对不同数据访问层的封装。使得表示层可以不关心具体的数据访问层。 2.业务逻辑数据的填充与转换。如管理员口令的加密。 3.核心业务的实现。这里很多业务逻辑只有一行代码,即一个业务逻辑方法恰好对应一 个数据访问方法,但是也有通过多个数据访问方法实现业务的。如 AdminBLL 中的 Chang ePassword 方法就调用了 AdminDAL 的 GetByID 和 Update 两个方法。另外,虽然许多方 法只调用一个数据访问方法,但是从命名看也能看出两者着眼点的不同。如 AdminDAL 中 的 GetByNameAndPassword, 这个名字显然是从数据库的角度看问题--指按照指定的 N ame 和 Password 两个字段的值取出相应信息, 至于这样做的业务意义它不需要知道。 A 而 dminBLL 中, 调用它的方法叫 Login, 这是从业务角度看问题--即这个方法是管理员登录。
下面分步骤实现业务逻辑层:
1.建立工程 在这个架构中,业务逻辑层是可以替换的。及业务逻辑层不是直接耦合于表示层,而是 通过依赖注入机制实现。所以,我们这里将这个业务逻辑层不直接命名为 BLL,而是新建一 个叫 SimpleBLL 的工程,放置我们这个业务逻辑层的相关代码。 2.配置依赖注入
业务逻辑层要通过反射工厂加载相应的数据访问层,这样就需要在 Web.config 中配置 需要使用的数据访问层。打开 Web.config,找到 appSettings 节点下的&DAL&项,将其中的 value 赋予我们要使用的数据访问层工程名称,例如:要使用 NBearDAL,则这一项应该这 样写:
3.编写散列加密工具类 因为在业务逻辑层的多处需要用到散列加密,所以在 Utility 工程下写一个辅助类 Encr yptor,完成这个工作,这个辅助类的具体代码如下: Encryptor.cs
1using S 2using System.Collections.G 3using System.T 4 5namespace NGuestBook.Utility 6{ 7 8 /**////
/// 辅助类-用于对敏感数据进行 Hash 散列,达到加密效果
9 10 11 12 13
public sealed class Encryptor { /**////
/// 使用 MD5 算法求 Hash 散列
明文 /// &returns&散列值&/returns&
public static string MD5Encrypt(string text) { return System.Web.Security.FormsAuthentication.HashPasswordForStori
ngInConfigFile(text, &MD5&); 20 21 22 23 /**////
/// 使用 SHA1 算法求 Hash 散列 }
明文 /// &returns&散列值&/returns&
public static string SHA1Encrypt(string text) { return System.Web.Security.FormsAuthentication.HashPasswordForStori
ngInConfigFile(text, &SHA1&); 30 31 32} } }
4.实现业务逻辑层
有了上述准备工作和以前实现的组件, 业务逻辑层的实现非常直观。 这里仅以管理员为 例,展示如何实现业务逻辑层。 AdminBLL 类建立在 SimpleBLL 工程下的 AdminBLL.cs 文件中,实现了 IAdminBLL 接口,需具体代码如下: IAdminBLL
1using S 2using System.Collections.G 3using System.T 4using NGuestBook.E 5using NGuestBook.F 6using NGuestBook.IBLL; 7using NGuestBook.IDAL; 8using NGuestBook.U 9 10namespace NGuestBook.IBLL 11{ 12 13 /**////
/// 业务逻辑层接口-管理员
14 15 16 17
public class AdminBLL : IAdminBLL { /**////
/// 添加管理员
新管理员实体类 /// &returns&是否成功&/returns&
22 23 24 25 26 27 28 29
public bool Add(AdminInfo admin) { admin.Password = Encryptor.MD5Encrypt(admin.Password); return DALFactory.CreateAdminDAL().Insert(admin); }
/// 删除管理员
欲删除的管理员的 ID /// &returns&是否成功&/returns&
33 34 35 36 37 38 39
public bool Remove(int id) { return DALFactory.CreateAdminDAL().Delete(id); }
/// 修改管理员密码
40 41 42 43
欲修改密码的管理员的 ID ///
新密码 /// &returns&是否成功&/returns&
44 45 46 47 48 49 50 51 52 53
public bool ChangePassword(int id, string password) { password = Encryptor.MD5Encrypt(password); AdminInfo admin = DALFactory.CreateAdminDAL().GetByID(id); admin.Password = return DALFactory.CreateAdminDAL().Update(admin); }
/// 管理员登录
54 55 56 57
管理员登录名 ///
管理员密码 /// &returns&如果登录成功,则返回相应管理员的实体类,否则返回 null&/returns&
58 59 60 61
public AdminInfo Login(string name, string password) { password = Encryptor.MD5Encrypt(password); return DALFactory.CreateAdminDAL().GetByNameAndPassword(name, p
assword); 62 63 64 65 /**////
/// 取得全部管理员信息 }
/// &returns&管理员实体类集合&/returns&
68 69 70 71 72 73} }
public IList GetAll() { return DALFactory.CreateAdminDAL().GetAll(); }
表示层实现
在这篇文章中,将讨论一下表示层的实现方法。 表示层是一个系统的&门脸&,不论你的系统设计的多么优秀,代码多么漂亮,系统的可 扩展性多么高,但是最终用户接触到的大多是表示层的东西。所以,表示层的优劣对于用户 最终对系统的评价至关重要。一般来说,表示层的优劣有一下两个评价指标: 1.美观。即外观设计漂亮,能给人美的感觉。 2.易用。即具有良好的用户体验,用户用起来舒服、顺手。 表示层的设计牵扯到很多非技术性问题,如美工、用户心理学等问题,但是在这篇文章 中,将不过多涉及这些问题,一来是我的水平有限,二来是这些内容和本系列文章的关系不 是很密切。这里将主要从技术实现的角度讨论表示层的设计。 一般来说,表示层的职责有以下两点: 1.接受用户的输入。 2.向用户呈现信息。 总体来说,就是与用户的交互。 而表示层的实现技术也是多种多样的,如 C/S 架构下一般使用 Windows 窗体技术(甚 至是命令行窗体),而 B/S 架构下主要是使用 Web 页的形式实现。而且在 Aj}

我要回帖

更多关于 java三层架构怎么搭建 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信