深入浅出C#三层架构

原文出处:http://blog.csdn.net/l0veit/article/details/7758012
本文用一个示例来介绍如何建设一个三层架构的项目,并说明项目中各个文件所处的层次与作用。写本文的目的,不是为了说明自己的这个方法有多对,而是希望给那些初学三层架构却不知从何入手的朋友提供一点帮助。因为网上的文章,大多是注重理论的介绍,而忽略了具体的实践应用,或者有示例但讲得不透彻。导致看了之后,理论上又学习了一遍,但还是不知道代码怎么写。所以想从这个方面入手写一下,让从来没做过三层架构的初学者也能照猫画虎,写出代码来。文中的代码是伪代码,仅用来阐明思路。

   正文:
一提三层架构,大家都知道是表现层(UI),业务逻辑层(BLL)和数据访问层(DAL),而且每层如何细分也都有很多的方法。但具体代码怎么写,到底那些文件算在哪一层,却是模模糊糊的。下面用一个简单的例子来带领大家实战三层架构的项目,这个例子只有一个功能,就是用户的简单管理。
首先建立一个空白解决方案,添加如下项目及文件

1
、添加ASP.NET Web Application项目,命名为UI,新建Web Form类型文件User.aspx(含User.aspx.cs

2
、添加ClassLibrary项目,命名为BLL,新建Class类型文件UserBLL.cs

3
、添加ClassLibrary项目,命名为DAL,新建Class类型文件UserDAL.cs。添加SQLHelper引用。(这个是微软的数据访问类,也可以不用,直接编写所有的数据访问代码。我一般用自己写的数据访问类DataAccessHelper)。

4
、添加ClassLibrary项目,命名为Model,新建Class类型文件UserModel.cs

5
、添加ClassLibrary项目,命名为IDAL,新建Interface类型文件IUserDAL.cs

6
、添加ClassLibrary项目,命名为ClassFactory

相信大家已经看出来了,这个和Petshop的示例没什么区别,而且更简单,因为在下也是通过Petshop学习三层架构的。但一些朋友对于这几个项目所处的层次,以及它们之间的关系,可能比较模糊,这里逐个说明一下:

1
User.aspxUser.aspx.cs

这两个文件(以及文件所属的项目,下面也是如此,不再重复强调了)都属于表现层部分。User.aspx比较好理解,因为它就是显示页面了。User.aspx.cs有些人觉得不应该算,而是要划到业务逻辑层中去。如果不做分层的话,那么让User.aspx.cs来处理业务逻辑,甚至操作数据库都没什么问题,但是做分层的话,这样就不应该了。在分层结构中,User.aspx.cs仅应该处理与显示有关的内容,其它部分都不应该涉及。

举例:我们实现用列表方式显示用户的功能,那么提取信息的工作是由BLL来做的,UI(本例中是User.aspx.cs)调用BLL得到UserInfo后,通过代码绑定到User.aspx的数据控件上,就实现了列表的显示。在此过程中User.aspx.csUI没有起到什么作用,仅是用来传递数据,而且因为实际编码中大部分情况都是如此的实现,所以使有些人觉得User.aspx.cs不应该算UI,而应该并入BLL负责逻辑处理。继续往下看,这时提出了一个新需求,要求在每个用户的前面加一个图标,生动地表现出用户的性别,而且不满18岁的用儿童图标表示。这个需求的实现,就轮到User.aspx.cs来做了,这种情况下User.aspx.cs才算有了真正的用途。

2
NewBLL.cs

添加如下方法:

public IList<UserInfo> GetUsers()
:返回所有的用户信息列表

public UserInfo GetUser(int UserId)
:返回指定用户的详细信息

public bool AddUser(UserInfo User)
:新增用户信息

public bool ChangeUser(UserInfo User)
:更新用户信息

public void RemoveUser(int UserId)
:移除用户信息

此文件就属于业务逻辑层了,专门用来处理与业务逻辑有关的操作。可能有很多人觉得这一层唯一的用途,就是把表现层传过来的数据转发给数据层。这种情况确实很多,但这只能说明项目比较简单,或者项目本身与业务的关系结合的不紧密(比如当前比较流行的MIS),所以造成业务层无事可做,只起到了一个转发的作用。但这不代表业务层可有可无,随着项目的增大,或者业务关系比较多,业务层就会体现出它的作用来了。

此处最可能造成错误的,就是把数据操作代码划在了业务逻辑层,而把数据库作为了数据访问层。

举例:有些朋友感觉BLL层意义不大,只是将DAL的数据提上来就转发给了UI,而未作任何处理。看一下这个例子

BLL


SelectUser
UserInfo userInfo)根据传入的usernameemail得到用户详细信息。

IsExist
UserInfo userInfo)判断指定的usernameemail是否存在。

然后DAL也相应提供方法共BLL调用

SelectUser
UserInfo userInfo

IsExist
UserInfo userInfo

这样BLL确实只起到了一个传递的作用。

但如果这样做:

BLL.IsExist
Userinfo userinfo

{

UerInfo user = DAL.SelectUser
User);


return (userInfo.Id != null);

}

那么DAL就无需实现IsExist()方法了,BLL中也就有了逻辑处理的代码。

3
UserModel.cs

实体类,这个东西,大家可能觉得不好分层。包括我以前在内,是这样理解的:UIßàModelßàBLLßàModelßàDAL,如此则认为Model在各层之间起到了一个数据传输的桥梁作用。不过在这里,我们不是把事情想简单,而是想复杂了。

Model
是什么?它什么也不是!它在三层架构中是可有可无的。它其实就是面向对象编程中最基本的东西:类。一个桌子是一个类,一条新闻也是一个类,intstringdoublie等也是类,它仅仅是一个类而已。

这样,Model在三层架构中的位置,和intstring等变量的地位就一样了,没有其它的目的,仅用于数据的存储而已,只不过它存储的是复杂的数据。所以如果你的项目中对象都非常简单,那么不用Model而直接传递多个参数也能做成三层架构。

那为什么还要有Model呢,它的好处是什么呢。下面是思考一个问题时想到的,插在这里:

Model在各层参数传递时到底能起到做大的作用?

在各层间传递参数时,可以这样:

AddUser
userIduserNameuserPassword,)

也可以这样:

AddUser
userInfo

这两种方法那个好呢。一目了然,肯定是第二种要好很多。

什么时候用普通变量类型(int,string,guid,double)在各层之间传递参数,什么使用Model传递?下面几个方法:

SelectUser
int UserId

SelectUserByName
string username

SelectUserByName
string usernamestring password

SelectUserByEmail
string email

SelectUserByEmail
string emailstring password

可以概括为:

SelectUser
userId

SelectUser
user

这里用user这个Model对象囊括了usernamepasswordemail这三个参数的四种组合模式。UserId其实也可以合并到user中,但项目中其它BLL都实现了带有id参数的接口,所以这里也保留这一项。

传入了userInfo,那如何处理呢,这个就需要按照先后的顺序了,有具体代码决定。

这里按这个顺序处理

首先看是否同时具有usernamepassword,然后看是否同时具有emailpassword,然后看是否有username,然后看是否有email。依次处理。

这样,如果以后增加一个新内容,会员卡(number),则无需更改接口,只要在DAL的代码中增加对number的支持就行,然后前台增加会员卡一项内容的表现与处理即可。

4
UserDAL.cs

public IList<UserInfo> SelectUsers()
:返回所有的用户信息列表(返回的一个泛型列表,可以进行序列化等操作)

public UserInfo SelectUser(int UserId)
:返回指定用户的相信信息(通过ID,返回实体类的实例相关信息)

public bool InsertUser(UserInfo User)
:新增用户信息(不同于Select,因为增加和更新是不会返回实体数据,只返回一个bool值表明操作是否成功)

public bool UpdateUser(UserInfo User)
:更新用户信息(同上)

public void DeleteUser(int UserId)
:移除用户信息(这个)

很多人最闹不清的就是数据访问层,到底那部分才算数据访问层呢?有些认为数据库就是数据访问层,这是对定义没有搞清楚,DAL是数据访问层而不是数据存储层,因此数据库不可能是这一层的。也有的把SQLHelper(或其同类作用的组件)作为数据访问层,它又是一个可有可无的东西,SQLHelper的作用是减少DAL层的重复性编码,提高编码效率,因此如果我习惯在乎效率或使用一个非数据库的数据源时,可以丢弃SQLHelper,一个可以随意弃置的部分,又怎么能成为三层架构中的一层呢。

可以这样定义:与数据源操作有关的代码,就应该放在数据访问层中,属于数据访问层

5
IUserDAL

数据访问层接口,这又是一个可有可无的东西,因为Petshop中带了它和ClassFactory类工厂,所以有些项目不论需不需要支持多数据源,都把这两个东西做了进来,有的甚至不建ClassFactory而只建了IDAL,然后“IUserDAL iUserDal = new UserDAL();”,不知意义何在。这就完全是画虎不成反类犬了。

许多人在这里有一个误解,那就是以为存在这样的关系:BLLßàIDALßàDAL,认为IDAL起到了BLLDAL之间的桥梁作用,BLL是通过IDAL来调用DAL的。但实际是即使你如此编码:“IUserDAL iUserDal = ClassFacotry.CreateUserDAL(),那么在执行“iUserDal.SelectUsers()”时,其实还是执行的UserDAL实例,而不是IUserDAL实例,所以IDAL在三层中的位置是与DAL平级的关系。

通过上面的介绍,基本上将三层架构的层次结构说明了。其实,本人有一个判断三层架构是否标准的方法,那就是将三层中的任意一层完全替换,都不会对其它两层造成影响,这样的构造基本就符合三层标准了(虽然实现起来比较难^_^)。例如如果将项目从B/S改为C/S(或相反),那么除了UI以外,BLLDAL都不用改动;或者将SQLServer改为Oracle,只需替换SQLServerDALOracleDAL,无需其它操作等等。

总结:不要因为某个层对你来说没用,或者实现起来特别简单,就认为它没有必要,或者摒弃它,或者挪作它用。只要进行了分层,不管是几层,每一层都要有明确的目的和功能实现,而不要被实际过程所左右,造成同一类文件位于不同层的情况发生。也不要出现同一层实现了不同的功能的情况发生。

 我自己补充点代码让大家看看三层式如何调用的,(一般我从DAL开始写,其实我觉得更应该从BLL层开始写,那样才更加明了你的项目的需求是哪些,BBL本来就是业务逻辑层嘛)

第一步:DAL层的一个方法:(注意看注释)

 



 

 先给点SQLHelpher的方法给大家看看先:(注意参数和返回类型,增删改都是返回影响行数)

[csharp] view plaincopy
  1. /// <summary>  
  2.         /// 执行无参SQL语句,并返回执行行数  
  3.         /// </summary>  
  4.         public static int GetScalar(string safeSql)  
  5.         {  
  6.             SqlCommand cmd = new SqlCommand(safeSql, Connection);  
  7.             int result = Convert.ToInt32(cmd.ExecuteScalar());  
  8.             return result;  
  9.         }  
  10.         /// <summary>  
  11.         /// 执行有参SQL语句,并返回执行行数  
  12.         /// </summary>  
  13.         public static int GetScalar(string sql, params SqlParameter[] values)  
  14.         {  
  15.             SqlCommand cmd = new SqlCommand(sql, Connection);  
  16.             cmd.Parameters.AddRange(values);  
  17.             int result = Convert.ToInt32(cmd.ExecuteScalar());  
  18.             return result;  
  19.         }  
  20.         /// <summary>  
  21.         /// 执行无参SQL语句,并返SqlDataReader  
  22.         /// </summary>  
  23.         public static SqlDataReader GetReader(string safeSql)  
  24.         {  
  25.             SqlCommand cmd = new SqlCommand(safeSql, Connection);  
  26.             SqlDataReader reader = cmd.ExecuteReader();  
  27.             return reader;  
  28.         }  


 

 再给个Model层的实体类:

[csharp] view plaincopy
  1. [Serializable]  
  2.    public class RoomType  
  3.    {  
  4.        protected int typeId;  
  5.        protected string typeName = String.Empty;  
  6.   
  7.        public RoomType()  
  8.        {  
  9.        }  
  10.         
  11.        public int TypeId  
  12.        {  
  13.            get { return typeId; }  
  14.            set { typeId = value; }  
  15.        }  
  16.   
  17.        public string TypeName  
  18.        {  
  19.            get { return typeName; }  
  20.            set { typeName = value; }  
  21.        }  
  22.   
  23.   
  24. }  



第二步:.看看BLL如何调用DAL的方法(如上所说,DAL只做数据查询,BLL才涉及到逻辑判断和推理

 

[csharp] view plaincopy
  1. /// <summary>  
  2.       /// 根据类型ID的房间信息集合  
  3.       /// </summary>  
  4.       public static IList<Room> GetAllRoomsByTypeId(int roomTypeId)  
  5.       {  
  6.           try  
  7.           {  
  8.               return RoomService.GetAllRoomsByTypeId(roomTypeId);  
  9.           }  
  10.           catch (Exception ex)  
  11.           {  
  12.               throw new Exception(ex.ToString());  
  13.           }  
  14.       }  
  15.       /// <summary>  
  16.       /// 得到房间信息集合  
  17.       /// </summary>  
  18.       public static IList<Room> GetAllRooms()  
  19.       {  
  20.           try  
  21.           {  
  22.               return RoomService.GetAllRooms();  
  23.           }  
  24.           catch (Exception ex)  
  25.           {  
  26.               throw new Exception(ex.ToString());  
  27.           }  
  28.       }  
  29.       /// <summary>  
  30.       /// 根据房间ID得到客房信息实体对象  
  31.       /// </summary>  
  32.       public static Room GetRoomByRoomId(int roomId)  
  33.       {  
  34.           try  
  35.           {  
  36.               return RoomService.GetRoomByRoomId(roomId);  
  37.           }  
  38.           catch (Exception ex)  
  39.           {  
  40.               throw new Exception(ex.ToString());  
  41.           }  
  42.       }  


 

 第三步:Web层(UI) ,只是把BLL层得到的数据给绑定到Web控件就ok了,只做页面布局和数据绑定相关的事情(如监听按钮事件,设置Style的风格,其实完全可以结合DOM、JQuery、Javascript来实现更加优异,这里只是给大家讲解框架)

 

[csharp] view plaincopy
  1. /// <summary>  
  2.     /// 执行GridView数据行绑定事件  
  3.     /// </summary>  
  4.     protected void gvRoom_RowDataBound(object sender, GridViewRowEventArgs e)  
  5.     {  
  6.         if (e.Row.RowType == DataControlRowType.DataRow)  
  7.         {  
  8.             //设置行颜色     
  9.             e.Row.Attributes.Add("onmouseover""currentcolor=this.style.backgroundColor;this.style.backgroundColor='#ff9900'");  
  10.             //添加自定义属性,当鼠标移走时还原该行的背景色     
  11.             e.Row.Attributes.Add("onmouseout""this.style.backgroundColor=currentcolor");  
  12.             //添加删除确认  
  13.             ImageButton imgbtn = (ImageButton)e.Row.FindControl("imgbtnDelete");  
  14.             imgbtn.Attributes.Add("onclick""return confirm('您确认要删除吗?');");  
  15.         }  
  16.     }  
  17.     /// <summary>  
  18.     /// 执行GridView数据行按钮事件  
  19.     /// </summary>  
  20.     protected void gvRoom_RowCommand(object sender, GridViewCommandEventArgs e)  
  21.     {  
  22.         //获取命令名称  
  23.         string cmd = e.CommandName;  
  24.         int roomId = Convert.ToInt32(e.CommandArgument);//获取命令参数  
  25.         if (cmd == "De")  
  26.         {  
  27.             //根据客房ID删除客房信息  
  28.             RoomManager.DeleteRoomByRoomId(roomId);  
  29.         }  
  30.         else if (cmd == "Ed")  
  31.         {  
  32.             //跳转到客房信息编辑页  
  33.             //此处使用的是Transfer  
  34.             Page.Server.Transfer("EditRoom.aspx?roomid=" +roomId.ToString());  
  35.         }  
  36.         BindRoom();  
  37.     }  
  38.     /// <summary>  
  39.     /// 执行分页事件  
  40.     /// </summary>  
  41.     protected void gvRoom_PageIndexChanging(object sender, GridViewPageEventArgs e)  
  42.     {  
  43.         gvRoom.PageIndex = e.NewPageIndex;  
  44.         BindRoom();  
  45.     }  


 

 杂项总结:上面所说到的接口(Interface/Factory),其实现实中除非大中型项目最好用到,小型项目都可以不需要,因为接口总体来说也是为了更好的实现松耦合和方法的调用效率(说白了就是为了后期代码好维护和性能的提升(说不定还要牺牲性能))  ;  基本所有框架都是为了松耦合实现代码功能分离,不同项目类型适合不同框架,总的都是为了同一个目标:代码维护方便;  所以很多项目是牺牲了系统性能来提升代码的优良结构

  哦 ,多说一点,上面的泛型和相关类可以进行序列化  [Serializable] 来进行更好的网络数据传输 ,相关文档大家去看看相关文献。

 

 

 

 

 引用文章:如下

 

 

·                                 浅析C#中三层架构的实现

·                                 http://developer.51cto.com  2008-12-09 14:18  佚名  中国IT教育整理  我要评论(1)

本文讨论如何在C#中实现三层架构,使用MS Access数据库存储数据。同时在三层架构中实现一个小型的可复用的组件来保存客户数据,并提供添加、更新、查找客户数据的功能。

这篇文章讨论如何在C#中实现三层架构,使用MS Access数据库存储数据。在此,我在3层架构中实现一个小型的可复用的组件保存客户数据。并提供添加,更新,查找客户数据的功能。

背景

首先,我介绍一些3层架构的理论知识。简单说明:什么是3层架构?3层架构的优点是什么?

什么是三层架构?

3层架构是一种“客户端-服务器”架构,在此架构中用户接口,商业逻辑,数据保存以及数据访问被设计为独立的模块。主要有3个层面,第一层(表现层,GUI层),第二层(商业对象,商业逻辑层),第三层(数据访问层)。这些层可以单独开发,单独测试。

为什么要把程序代码分为3层。把用户接口层,商业逻辑层,数据访问层分离有许多的优点。

在快速开发中重用商业逻辑组件,我们已经在系统中实现添加,更新,删除,查找客户数据的组件。这个组件已经开发并且测试通过,我们可以在其他要保存客户数据的项目中使用这个组件。

系统比较容易迁移,商业逻辑层与数据访问层是分离的,修改数据访问层不会影响到商业逻辑层。系统如果从用SQL Server存储数据迁移到用Oracle存储数据,并不需要修改商业逻辑层组件和GUI组件

系统容易修改,假如在商业层有一个小小的修改,我们不需要在用户的机器上重装整个系统。我们只需要更新商业逻辑组件就可以了。

应用程序开发人员可以并行,独立的开发单独的层。

代码

这个组件有3层,第一个层或者称为GUI层用form实现,叫做FrmGUI。第二层或者称为商业逻辑层,叫做BOCustomer,是Bussniess Object Customer的缩写。最后是第三层或者称为数据层,叫做DACustomer,是Data Access Customer的缩写。为了方便,我把三个层编译到一个项目中。

用户接口层

下面是用户接口成的一段代码,我只选取了调用商业逻辑层的一部分代码。

//This function get the details from the user via GUI

//tier and calls the Add method of business logic layer.

private void cmdAdd_Click(object sender, System.EventArgs e)

{

try

{

cus = new BOCustomer();

cus.cusID=txtID.Text.ToString();

cus.LName = txtLName.Text.ToString();

cus.FName = txtFName.Text.ToString();

cus.Tel= txtTel.Text.ToString();

cus.Address = txtAddress.Text.ToString();

cus.Add();

}

catch(Exception err)

{

MessageBox.Show(err.Message.ToString());

}

}

//This function gets the ID from the user and finds the

//customer details and return the details in the form of

//a dataset via busniss object layer. Then it loops through

//the content of the dataset and fills the controls.

private void cmdFind_Click(object sender, System.EventArgs e)

{

try

{

String cusID = txtID.Text.ToString();

BOCustomer thisCus = new BOCustomer();

DataSet ds = thisCus.Find(cusID);

DataRow row;

row = ds.Tables[0].Rows[0];

//via looping

foreach(DataRow rows in ds.Tables[0].Rows )

{

txtFName.Text = rows["CUS_F_NAME"].ToString();

txtLName.Text = rows["CUS_L_NAME"].ToString();

txtAddress.Text = rows["CUS_ADDRESS"].ToString();

txtTel.Text = rows["CUS_TEL"].ToString();

}

}

catch (Exception err)

{

MessageBox.Show(err.Message.ToString());

}

}

//this function used to update the customer details.

private void cmdUpdate_Click(object sender, System.EventArgs e)

{

try

{

cus = new BOCustomer();

cus.cusID=txtID.Text.ToString();

cus.LName = txtLName.Text.ToString();

cus.FName = txtFName.Text.ToString();

cus.Tel= txtTel.Text.ToString();

cus.Address = txtAddress.Text.ToString();

cus.Update();

}

catch(Exception err)

{

MessageBox.Show(err.Message.ToString());

}

}

商业逻辑层

下面是商业逻辑层的所有代码,主要包括定义customer对象的属性。但这仅仅是个虚构的customer对象,如果需要可以加入其他的属性。商业逻辑层还包括添加,更新,查找,等方法。

商业逻辑层是一个中间层,处于GUI层和数据访问层中间。他有一个指向数据访问层的引用cusData = new DACustomer().而且还引用了System.Data名字空间。商业逻辑层使用DataSet返回数据给GUI层。

[csharp] view plaincopy
  1. using System;  
  2.   
  3. using System.Data;  
  4.   
  5. namespace _3tierarchitecture  
  6.   
  7. {  
  8.   
  9. ///  
  10.   
  11. /// Summary description for BOCustomer.  
  12.   
  13. ///  
  14.   
  15. public class BOCustomer  
  16.   
  17. {  
  18.   
  19. //Customer properties  
  20.   
  21. private String fName;  
  22.   
  23. private String lName;  
  24.   
  25. private String cusId;  
  26.   
  27. private String address;  
  28.   
  29. private String tel;  
  30.   
  31. private DACustomer cusData;  
  32.   
  33. public BOCustomer()  
  34.   
  35. {  
  36.   
  37. //An instance of the Data access layer!  
  38.   
  39. cusData = new DACustomer();  
  40.   
  41. }  
  42.   
  43. ///  
  44.   
  45. /// Property FirstName (String)  
  46.   
  47. ///  
  48.   
  49. public String FName  
  50.   
  51. {  
  52.   
  53. get  
  54.   
  55. {  
  56.   
  57. return this.fName;  
  58.   
  59. }  
  60.   
  61. set  
  62.   
  63. {  
  64.   
  65. try  
  66.   
  67. {  
  68.   
  69. this.fName = value;  
  70.   
  71. if (this.fName == "")  
  72.   
  73. {  
  74.   
  75. throw new Exception(  
  76.   
  77. "Please provide first name ...");  
  78.   
  79. }  
  80.   
  81. }  
  82.   
  83. catch(Exception e)  
  84.   
  85. {  
  86.   
  87. throw new Exception(e.Message.ToString());  
  88.   
  89. }  
  90.   
  91. }  
  92.   
  93. }  
  94.   
  95. ///  
  96.   
  97. /// Property LastName (String)  
  98.   
  99. ///  
  100.   
  101. public String LName  
  102.   
  103. {  
  104.   
  105. get  
  106.   
  107. {  
  108.   
  109. return this.lName;  
  110.   
  111. }  
  112.   
  113. set  
  114.   
  115. {  
  116.   
  117. //could be more checkings here eg revmove ' chars  
  118.   
  119. //change to proper case  
  120.   
  121. //blah blah  
  122.   
  123. this.lName = value;  
  124.   
  125. if (this.LName == "")  
  126.   
  127. {  
  128.   
  129. throw new Exception("Please provide name ...");  
  130.   
  131. }  
  132.   
  133. }  
  134.   
  135. }  
  136.   
  137. ///  
  138.   
  139. /// Property Customer ID (String)  
  140.   
  141. ///  
  142.   
  143. public String cusID  
  144.   
  145. {  
  146.   
  147. get  
  148.   
  149. {  
  150.   
  151. return this.cusId;  
  152.   
  153. }  
  154.   
  155. set  
  156.   
  157. {  
  158.   
  159. this.cusId = value;  
  160.   
  161. if (this.cusID == "")  
  162.   
  163. {  
  164.   
  165. throw new Exception("Please provide ID ...");  
  166.   
  167. }  
  168.   
  169. }  
  170.   
  171. }  
  172.   
  173. ///  
  174.   
  175. /// Property Address (String)  
  176.   
  177. ///  
  178.   
  179. public String Address  
  180.   
  181. {  
  182.   
  183. get  
  184.   
  185. {  
  186.   
  187. return this.address;  
  188.   
  189. }  
  190.   
  191. set  
  192.   
  193. {  
  194.   
  195. this.address = value;  
  196.   
  197. if (this.Address == "")  
  198.   
  199. {  
  200.   
  201. throw new Exception("Please provide address ...");  
  202.   
  203. }  
  204.   
  205. }  
  206.   
  207. }  
  208.   
  209. ///  
  210.   
  211. /// Property Telephone (String)  
  212.   
  213. ///  
  214.   
  215. public String Tel  
  216.   
  217. {  
  218.   
  219. get  
  220.   
  221. {  
  222.   
  223. return this.tel;  
  224.   
  225. }  
  226.   
  227. set  
  228.   
  229. {  
  230.   
  231. this.tel = value;  
  232.   
  233. if (this.Tel == "")  
  234.   
  235. {  
  236.   
  237. throw new Exception("Please provide Tel ...");  
  238.   
  239. }  
  240.   
  241. }  
  242.   
  243. }  
  244.   
  245. ///  
  246.   
  247. /// Function Add new customer. Calls  
  248.   
  249. /// the function in Data layer.  
  250.   
  251. ///  
  252.   
  253. public void Add()  
  254.   
  255. {  
  256.   
  257. cusData.Add(this);  
  258.   
  259. }  
  260.   
  261. ///  
  262.   
  263. /// Function Update customer details.  
  264.   
  265. /// Calls the function in Data layer.  
  266.   
  267. ///  
  268.   
  269. public void Update()  
  270.   
  271. {  
  272.   
  273. cusData.Update(this);  
  274.   
  275. }  
  276.   
  277. ///  
  278.   
  279. /// Function Find customer. Calls the  
  280.   
  281. /// function in Data layer.  
  282.   
  283. /// It returns the details of the customer using  
  284.   
  285. /// customer ID via a Dataset to GUI tier.  
  286.   
  287. ///  
  288.   
  289. public DataSet Find(String str)  
  290.   
  291. {  
  292.   
  293. if (str == "")  
  294.   
  295. throw new Exception("Please provide ID to search");  
  296.   
  297. DataSet data = null;  
  298.   
  299. data = cusData.Find(str);  
  300.   
  301. return data;  
  302.   
  303. }  
  304.   
  305. }  
  306.   
  307. }  


数据访问层

数据层包括处理MS Access数据库的细节。所有这些细节都是透明的,不会影响到商业逻辑层。数据访问层有个指向商业逻辑层的引用BOCustomer cus。为了应用方便并且支持其他数据库。

[csharp] view plaincopy
  1. using System;  
  2.   
  3. using System.Data.OleDb;  
  4.   
  5. using System.Data;  
  6.   
  7. namespace _3tierarchitecture  
  8.   
  9. {  
  10.   
  11. ///  
  12.   
  13. /// Summary description for DACustomer.  
  14.   
  15. ///  
  16.   
  17. public class DACustomer  
  18.   
  19. {  
  20.   
  21. private OleDbConnection cnn;  
  22.   
  23. //change connection string as per the  
  24.   
  25. //folder you unzip the files  
  26.   
  27. private const string CnnStr =  
  28.   
  29. "Provider=Microsoft.Jet.OLEDB.4.0;Data " +  
  30.   
  31. "Source= D:\\Rahman_Backup\\Programming\\" +  
  32.   
  33. "Csharp\\3tierarchitecture\\customer.mdb;";  
  34.   
  35. //local variables  
  36.   
  37.    

本文转载:CSDN博客