零基础学C#3.0 -- .net的三层架构 - CodingPenguin
时间 2014-01-26 17:40:00 博客园-所有随笔区
原文 http://www.cnblogs.com/codingpenguin/p/3534304.html
主题 .Net 数据库
新手学C# ——.net的三层架构之最简单实例:登录界面
三层架构包括:
1. 数据访问层(Data Access Layer, DAL):负责将底层数据传送到业务逻辑层
2. 业务逻辑层(Business Logic Layer, BLL):处理数据访问层传送的数据,并实现业务逻辑
3. 表示层(User Interface, UI):不处理任何业务,负责显示与实时更新
其中1--2--3层次依次上升。
为了使信息能够顺利由底层传送,可以采用实体类的方法,添加实体层。实体类通常与数据库中字段相互对应,拥有get和set属性。实体类的目的是用于替代DataSet,通过类的方式传递数据,并使逻辑更加清晰。
三层架构来源于MVC,其核心思想是保持三层之间的相互独立,在对其他功能进行局部修改时,可以使三层结构保持大体不变,以免进行全局的修改。换句话说,在修改某局部代码后,你自然而然的知道 何处的代码应该进行修改 , 何处的代码可以不进行修改 , 如何规范修改的局部代码对上层的接口以达到减少修改量的目的 。
这里不得不说的是,在三层架构中,修改局部代码对整体的变动还是很大的,层次数越多,需要修改的部分越少。当然,层次数的增加伴随着逻辑的复杂性增加和接口的复杂性增加。越是小型的项目,需要的层次数越少。
下面举一个最简单的例子:用户登录。
数据库中表Login的结构:
LoginID : 用户名
LoginPwd : 用户密码
(1)新建一个WinForm项目SchoolManager,在项目解决方案中点击右键新建三个类库(SchoolManager.DAL, SchoolManager.BLL, SchoolManager.Model),分别表示数据访问层、业务逻辑层和实体层。
(2)右键单击类库,添加引用(BLL引用DAL,UI引用BLL,三者都引用Model),表达四者之间的逻辑依赖关系。这里强调的是,UI不引用DAL。
(3)编写实体类Login.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SchoolManager.Model
{
public class Login
{
private int stuID; //学号
public int StuID
{
get { return stuID; }
set { stuID = value; }
}
private string studentName; //姓名
public string StudentName
{
get { return studentName; }
set { studentName = value; }
}
private string loginID; //登录名
public string LoginID
{
get { return loginID; }
set { loginID = value; }
}
private string loginPwd; //登录密码
public string LoginPwd
{
get { return loginPwd; }
set { loginPwd = value; }
}
private int state;
public int State
{
get { return state; }
set { state = value; }
}
}
}这个实体类与数据库中的表一一对应(这里没有对应的原因是实际程序中只用到了两个字段,实际数据库中的表以此类中的字段为准),也就是说,数据库中表的每一行都可以转化为这个类中的一个实例,从而在各个层中传递数据。
(4)编写DAL类LoginService.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SchoolManager.Model;
using System.Data.SqlClient;
namespace SchoolManager.DAL
{
public static class LoginService
{
static string connStr = @"Data Source=(local)\SQLEXPRESS;Initial Catalog=StudentInfo;Integrated Security=True;Pooling=False";
private static SqlConnection sqlConn = new SqlConnection(connStr);
/// <summary>
/// 根据登录名返回用户类
/// </summary>
/// <param name="loginID">登录名</param>
/// <returns>用户类</returns>
public static Login GetLoginByLoginID(string loginID)
{
string sql = "select * from Login where LoginID='" + loginID + "'";
try
{
SqlCommand sqlCmd = new SqlCommand(sql, sqlConn);
sqlConn.Open();
SqlDataReader sqlReader = sqlCmd.ExecuteReader();
if (sqlReader.Read())
{
Login user = new Login();
user.LoginID = Convert.ToString(sqlReader["LoginID"]);
user.LoginPwd = Convert.ToString(sqlReader["LoginPwd"]);
user.State = Convert.ToInt32(sqlReader["State"]);
user.StudentName = Convert.ToString(sqlReader["StudentName"]);
user.StuID = Convert.ToInt32(sqlReader["StuID"]);
sqlReader.Close();
sqlConn.Close();
return user;
}
else
{
sqlConn.Close();
sqlReader.Close();
return null;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
}
}
}这里注意几点:
a)此类(以及之后的BLL,UI)引入了Model的命名空间,从而可以调用Model中的Login类并生成实例,这正是添加引用的原因所在。
b)此类引入了System.Data.SqlClient,也是这三层中唯一引用这个命名空间的层,即所有对数据库的操作都要在这一层的不同类中完成。
c)GetLoginByLoginIn()方法的返回值是Login类的一个实例,实质上是返回查询后的指定行数据。
(5)编写BLL类LoginManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SchoolManager.Model;
using SchoolManager.DAL;
namespace SchoolManager.BLL
{
public class LoginManager
{
/// <summary>
/// 从数据访问层调用数据的方法
/// </summary>
/// <param name="loginID">登录名</param>
/// <returns>密码是否匹配</returns>
public static bool GetLogin(string loginID, string loginPwd)
{
Login user = LoginService.GetLoginByLoginID(loginID);
if (user.LoginPwd == loginPwd)
{
return true;
}
else
{
return false;
}
}
}
}注意以下几点:
a)引用了DAL的命名空间,因为要调用DAL中的GetLoginByLoginIn()方法。
b)GetLogin()实际上已经完成了用户登录的逻辑功能,不能将判断式写入UI层中。
(6)编写UI层LoginForm.cs:(界面很简洁,用户名、密码输入框,确定、取消按钮)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SchoolManager.Model;
using SchoolManager.BLL;
namespace SchoolManager
{
public partial class LoginForm : Form
{
public LoginForm()
{
InitializeComponent();
}
private void buttonLogin_Click(object sender, EventArgs e)
{
//检测用户名是否为空
if(string.IsNullOrEmpty(textBoxName.Text))
{
MessageBox.Show("请输入用户名");
return;
}
//检测密码是否为空
if (string.IsNullOrEmpty(textBoxPwd.Text))
{
MessageBox.Show("请输入密码");
return;
}
//调用业务逻辑层方法登录
if(LoginManager.GetLogin(textBoxName.Text, textBoxPwd.Text))
{
MessageBox.Show("登陆成功");
}
else
{
MessageBox.Show("用户名或密码错误");
}
}
private void buttonCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
}这里有几点需要注意:
a)引用命名空间(详见上文)
b)对TextBox中是否为空的判断可以由UI层完成,也可以在BLL层中编写Validate()函数并在UI层中调用,不过还是建议在UI层中完成,毕竟界面的修改必然伴随着Validate()方法的修改
c)UI层调用GetLogin()方法之后,只是将返回的布尔值解释为登录成功/失败,没有进行逻辑上的判断。
希望本文能对.net学习的菜鸟级新手有所帮助!(本人也处于这一行列)