最近学习了三层结构,这三层结构分别是界面层(User Interface layer),业务逻辑层(Business Logic Layer),数据访问层(Data access layer)。为什么要分层,从官方角度来说就是降低前台于后端之间的耦合度,解释一下就是前台指界面层,后台可以理解为数据库,如果没有中间的逻辑层和数据访问层来分解的话,所有的事情基本上都是界面层在干,好比一个公司只有一个员工,那么这个公司的所有工作只有一个人来干,那么在资源有限情况下,任务处理速度自然无线降低,工作效率就自然不用说,如果一个公司有足够的员工,并且各司其职,同样的资源,却会发挥出更高的工作效率,自然任务处理速度增加。
界面层(UI):展示给用户的界面,可以接受用户输入信息,也给用户展示返回的信息。
业务逻辑层(BLL):调用相关的数据访问类,对数据层的操作和业务的处理,对用户输入的信息进行处理,并把返回值返回给界面层,实现用户所需功能。
数据访问层(DAL):直接操纵数据库,主要是曾删改查的功能,实现进本记录操作。
三层设计的优缺点:
优点:
1、开发人员可以只关注整个结构中的其中某一层;
2、可以很容易的用新的实现来替换原有层次的实现;
3、可以降低层与层之间的依赖;
4、有利于标准化;
5、利于各层逻辑的复用。
缺点:
1、降低了系统的性能。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。
三层实际操作:
引用:
路径:解决方案资源管理器视图→项目→右键单击,添加引用→项目→勾选项目名称单击确定即可。
UI:BLL,Model。BLL:DAL,Model。DAL:Model。提示:千万不要全部都引用,因为会出现循环引用错误,而且,用哪个引用哪个。不要多用,导致出现引用循环。
在写代码前需要说明的是,我的程序集名称是LoginBLL,默认命名空间是Login.BLL,中间多加了一个点,在实例化的过程中这是一个非常容易出错的地方,如果你不是自己写的代码,请注意命名规范。
首先我们来建立数据访问层(DAL):
Dbutil类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.DAL
{
class Dbutil
{
//登录SQL Server代码
public static string ConnString = @"Server=(Local); Database=Login; User=sa; Password=123456";
}
}
ScoreDAO类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace Login.DAL
{
public class ScoreDAO
{
public void UpdateScore(string userName,int value)//加分
{
//using 打开了数据库连接,从数据库中读取数据。
using (SqlConnection conn = new SqlConnection(Dbutil.ConnString))
{
//sqlcommand 表示可以对SQL Server数据库进行的操作。
SqlCommand cmd = conn.CreateCommand();
//获取数据表名
cmd.CommandText = @"INSERT INTO Score(UserName,Score) Values(@UserName,@Score)";
//声明两个参数. Parameters是范围的意思。
cmd.Parameters.Add(new SqlParameter("@UserName", userName));
cmd.Parameters.Add(new SqlParameter("@Score", value));
//登录数据库
conn.Open();
cmd.ExecuteNonQuery();//必须引用using System.Data.SqlClient;此代码用来更新数据库。
}
}
}
}
UserDAO类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace Login.DAL
{
public class UserDAO
{
//
public Login.Model.UserInfo SelectUser(string userName,string password)
{
//using 打开了数据库连接,从数据库中读取数据。
using(SqlConnection conn = new SqlConnection(Dbutil.ConnString))//此行代码是登录SQL Server用的
{
//sqlcommand 表示可以对SQL server数据库进行的操作
SqlCommand cmd = conn.CreateCommand();
//获取数据表名
cmd.CommandText = @"SELECT ID,UserName,Password,Email FROM USERS WHERE UserName=@UserName AND Password=@Password";
//二CommandType是一个枚举类型。有三个值:text,StoredProcedure,TableDirect用于标书SqlCommand对象Commandtype的执行形式。
cmd.CommandType = System.Data.CommandType.Text;//不写也可以的,因为Text是默认的
//声明两个参数。Parameters是范围的意思。查询条件。
cmd.Parameters.Add(new SqlParameter("@UserName", userName));
cmd.Parameters.Add(new SqlParameter("@Password", password));
//登录数据库
conn.Open();
//想要使用SQLDateReader,就必须引用上面的client命名空间。并且如果想创建SQLDateReader,就必须使用ExecuteReader方法。
SqlDataReader reader = cmd.ExecuteReader();//对数据库进行查询得到结果,并且返回对象。
Login.Model.UserInfo user = null;//先构造LoginModel,首先默认值为Null
while (reader.Read())//开始读取数据,如果用户名和密码不正确,无法读取数据,直接返回user为null
{
if(user==null)//如果null的话,在进行构造。
{
user = new Login.Model.UserInfo();
}
user.ID = reader.GetInt32(0);
user.UserName = reader.GetString(1);
user.Password = reader.GetString(2);
if (!reader.IsDBNull(3))
{
user.Email = reader.GetString(3);
}
}
return user;
}
}
}
}
业务逻辑层(BLL):
LoginManager类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.BLL
{
public class LoginManager
{
public Login.Model.UserInfo UserLogin(string userName,string password)//获取用户传来的信息
{
//需要和数据源打交道,实例化DAL层
Login.DAL.UserDAO uDao = new Login.DAL.UserDAO();
Login.Model.UserInfo user = uDao.SelectUser(userName, password);
if (user != null)//登录成功时
{
Login.DAL.ScoreDAO sDao = new Login.DAL.ScoreDAO();//增加积分。
sDao.UpdateScore(userName, 10);
return user;
}
else
{
throw new Exception("登录失败");//登录不成功跳到这里
}
}
}
}
界面层(UI):
注意命名,已经更改。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
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();
}
private void btnLogin_Click(object sender, EventArgs e)
{
string userName = txtUserName.Text.Trim();
string password = txtPassword.Text;
//实例化这个业务层类
Login.BLL.LoginManager mgr = new Login.BLL.LoginManager();
//将信息给model层
Login.Model.UserInfo user = mgr.UserLogin(userName, password);
//返回UI层
MessageBox.Show("登录用户:" + user.UserName);
}
}
}
Model层:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.Model
{
public class UserInfo
{
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
}
最后总结了一点,自己写代码的时候注意自己的命名规范,我在后边的时候,出现的错误基本上都是命名出现的错误,尤其是在借用别人的代码的时候,命名不一致的时候是最致命的,一般情况下会出现引用问题,但是有时候是using的,有时候是引用的程序集问题,数据库的链接符也比较容易出现命名不一致的问题,这是我对于三层第一次实践出现比较常见的问题。