三层简介:
何时使用:
当业务复杂,把数据存储到相应的数据库或者独立的数据存储介质,把数据库访问层脱离业务独立存在,业务脱离UI单独存在。
DAL(数据访问层):访问所有的数据源。
作用:一,从数据源加载数据(Select)二,向数据源写入数据(Insert/Update)三,从数据源删除数据(Delete)(除了这些基本的数据访问,其他一概不管)
BLL(业务逻辑层):
作用:一,从DAL中获取数据,以供UI显示用。二,从UI中获取用户指令和数据,执行业务逻辑。三,从UI中获取用户指令和数据,通过DAL写入数据源。(负责处理业务逻辑。通过获取UI传来的操作指令,决定执行业务逻辑,在需要访问数据源的时候直接交给DAL处理。处理完成后,返回必要数据给UI。)
BLL职责机制:
一:UI--->BLL--->DAL--->BLL--->UI:UI提出请求并搜集一定的用户数据传给BLL,BLL处理不了需要访问数据源,把请求转给DAL,DAL经过数据源访问加工,转给BLL,BLL得到想要的结果,把结果返回给UI。
二:UI--->BLL--->UI:UI给BLL,BLL能处理经过加工处理直接给UI。
UI(显示层):用户至上,兼顾简洁
作用:一,向用户展现特定业务数据。二,采集用户的输入信息和操作。(只负责显示和采集用户操作,不包含任何的业务相关的逻辑处理。)
各个层之间的引用关系:UI--->BLL--->DAL
DAL所在程序集不引用BLL和UI。
BLL需要引用DAL
UI直接引用BLL,可能会间接引用DAL
实际演练:
LoginUI:界面,只负责显示和采集用户操作,完成数据输入与输出。
F o r m 1 . c s:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LoginUI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();//初始化FORM
}
private void btnLogin_Click(object sender, EventArgs e)
{//显示层不能和数据源直接打交道,所以需要业务逻辑层来支持。
//IDbConnection conn = new SqlConnection();
//IDbCommand cmd = conn.CreateCommand();
//cmd.CommandText = "Select UserName From USERS WHERE ...";
//cmd.ExecuteReader();
//Trim函数移除两侧空白
string userName = txtUserName.Text.Trim();
string password = txtPassword.Text;
//转至.BLL(业务逻辑层) UI提出请求并搜集一定的用户数据传给BLL(业务逻辑层)
Login.BLL.LoginManager mgr = new Login.BLL.LoginManager();
//Model是用来传输数据的业务数据模型 //BLL得到想要的结果,把结果返回给UI。
Login.Model.UserInfo user= mgr.UserLogin(userName, password);
MessageBox.Show("登录用户:" +user.UserName);
}
}
}
P r o g r a m . c s :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LoginUI
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
LoginBLL:处理业务逻辑,调用DAL处理数据,实现从UI到DAL的数据传输,在一定程度上解耦,解除客户端和数据库的耦合。
LoginManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.BLL
{
public class LoginManager
{//User数据模型。
public Login.Model.UserInfo UserLogin(string userName,string password)
{
Login.DAL.UserDAO uDao = new Login.DAL.UserDAO();
Login.Model.UserInfo user= uDao.SelectUser(userName, password);
//DAL经过数据源访问加工,转给BLL.证明数据库有User
if (user!=null)//login successfully(登录成功)加10分
{
Login.DAL.ScoreDAO sDao = new Login.DAL.ScoreDAO();
sDao.UpdateScore(userName, 10);//BLL转到DAL进行加分
return user;
}
else
{//自己写的抛出错误的原因
throw new Exception("登录失败");
//MessageBox.Show( user.UserName + "登录失败:");
}
}
}
}
LoginDAL:与具体的数据库打交道,对数据进行插入和读取。
DbUtil.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.DAL
{
class DbUtil
{
public static string ConnString = @"Server=DESKTOP-GFAMGHI;Database=Login;User ID =sa;Password=123456";
}
}
ScoreDAO.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
namespace Login.DAL
{
public class ScoreDAO
{
public void UpdateScore(string userName,int value)
{
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))//创建连接,数据库连接对象conn
{
SqlCommand cmd = conn.CreateCommand();//创建命令
//往表中插入数据.
cmd.CommandText = @"INSERT INTO SCORES(UserName,Score)Values(@UserName,@Score)";//设置操作语句
cmd.Parameters.Add(new SqlParameter("@UserName", userName));//添加参数
cmd.Parameters.Add(new SqlParameter("@Score", value));//设置参数值
conn.Open();//打开链接
cmd.ExecuteNonQuery(); //执行命令,增删改操作。
}
}
}
}
UserDAO.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace Login.DAL
{
public class UserDAO
{//BLL处理不了,把请求转给DAL,DAL访问数据源.
public Login.Model.UserInfo SelectUser(string userName,string password)
{
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))//创建连接
{
SqlCommand cmd = conn.CreateCommand();//创建命令
cmd.CommandText = @"SELECT ID,UserName,Password,Email
FROM USERS WHERE UserName=@UserName AND Password = @Password";//设置操作语句
cmd.CommandType = CommandType.Text;//CommandType是SqlCommand对象的一个属性,
//用于指定执行动作的形式,它告诉.net接下来执行的是一个文本(text)
cmd.Parameters.Add(new SqlParameter("@UserName", userName));//添加参数
cmd.Parameters.Add(new SqlParameter("@Password", password));//设置参数值
conn.Open();//打开连接,这里是基于链接的数据库访问模式。
SqlDataReader reader = cmd.ExecuteReader(); //执行命令,增删改操作//通过SqlDataReader类依次读取。
Login.Model.UserInfo user = null;
//读取数据
while (reader.Read())//遍历所有记录
{
if (user == null)
{
user = new Login.Model.UserInfo();
}
user.ID = reader.GetInt32(0);//取那一列第一个数
user.UserName = reader.GetString(1);//按照string类型读取
user.Password = reader.GetString(2);
if (!reader.IsDBNull(3))
{
user.Email = reader.GetString(3);
}
}
return user;
}
}
}
}
LoginModel:用来传输数据的业务数据模型,为了避免三层之间的互相引用,独立于其他层的,其他层都会引用Model。
UserInfo.cs:
namespace Login.Model
{//Model是为了在三层之间传输数据的,他是独立与其他三个层次的。LoginModel不会引用任何程序集的。而其他的都会引用这个。
public class UserInfo
{//.net3.0支持这种写法:
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
}
分析:最关键的是BLL层,三层的优势是职责分离,降低耦合。就像是一个餐厅,UI是服务员,我们任何需求都给服务员说,他相当于交互操作界面。服务员把菜单转给厨师,厨师就相当于BLL(业务逻辑层)负责业务处理和数据传递,比如告诉采购员DAL(数据访问层)白菜不够了,采购员就往仓库(数据库)中添加白菜(数据)。采购员对仓库进行操作。