一、實例:
現在有一個積分系統,學生每登錄一次可獲得10積分獎勵。
這個實例只是簡單的三層登錄,每次登錄成功就加10,不涉及其他的功能,當然,其中可能也有很多bug需要優化。
1.數據庫表設計:
2.數據模塊圖:
細心的讀者肯定會發現,除了UI,BLL,DAL這三個之外還有一個Model存在,這個Model不屬於任何一層,只是爲了更好地鏈接三層而存在的。這個類只存儲,與以上三類共同使用的東西。起一個協調的作用。Model類,也就是實體類Entity。
3.這幾個層次的關係:
二、源代碼分析
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; }
}
}
UI 層:登錄
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;//Windows.Froms的命令空間
namespace LoginUI
{
public partial class Form1 : Form
{
public Form1()
{
//初始化窗體上的所有控件
InitializeComponent();
}
private void btnLogin_Click(object sender, EventArgs e)
{
//獲得登錄窗體的用戶名 Trim去空格操作,注意和VB的形式不一樣
string userName = txtUserName.Text.Trim();
//因爲密碼中可能是空格所以不用去空格操作
string password = txtpassword.Text;
//實例化業務邏輯層的對象mgr,讓業務邏輯層去判斷輸入內容
Login.BLL.LoginManager mgr = new Login.BLL.LoginManager();
//用戶輸入的內容通過mgr調用業務邏輯層的UserLogin方法,屬於拿來主義。B層會去調用D層
mgr.UserLogin(userName, password);
//和Model 交互,將數據層的信息傳入Model
Login.Model.UserInfo user = mgr.UserLogin(userName ,password );
//登錄成功提示登錄成功
MessageBox.Show("登錄用戶:"+userName );
}
}
}
注意:UI 代碼中(B層和D層也有)涉及到與B層交互,以及與Model層交互,代碼表示爲:Login.BLL.LoginManager 和 Login.Model.UserInfo,這裏有個要討論的點:
爲什麼要寫成命名空間+類名?直接把命名空間用using引用進來可以嗎?
答:直接引入命名空間是可以的,並且直接引入命名空間之後,涉及到這兩類的所有對象,都不用再寫其命名空間+類名了,這樣就體現了一個複用的思想,不用每次都寫命名空間。
這也就是類和類之間交互,需要跨類庫找類時一個路徑問題,先找到類所在的位置,再找類名。當然,我們在同一層(同一個類庫)下,調用不同類的對象,就不需要先找路徑(不需要寫命名空間),這就像我們在同一個文件下找不同文件,他們的路徑都是一樣的,不需要我們再去找路徑。
B層:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.BLL//業務邏輯層:要與數據訪問層交互,去調數據庫,從而判斷用戶輸入的賬戶密碼是否數據庫中存在
{
public class LoginManager//登錄管理
{
//定義一個方法UserLogin,返回值是Login.Model.UserInfo類型的對象
public Login.Model.UserInfo UserLogin(string userName,string password)
{
//先實例化一個D層的對象
Login.DAL.UserDAO uDao = new Login.DAL.UserDAO();
//通過UI中填寫的內容,調用SelectUser方法,返回相應的數據
Login.Model.UserInfo user =uDao.SelectUser(userName ,password );//返回了user,含數據庫中的內容
if(user!=null)//登錄成功
{
//登錄成功,便給此用戶加10分,並且返回user
//與D層交互,實例化D層 一個加分對象
Login.DAL.ScoreDAO sDao = new Login.DAL.ScoreDAO();
//調用加分方法,加10分
sDao.UpdateScore(userName, 10);
return user;
}
else //若數據庫中沒有該用戶名,則登錄失敗
{
throw new Exception("登錄失敗");
}
}
}
}
D層:三個類:
class DbUtil:用於保存連接服務器的SQL語句
class UserDAO:訪問數據庫—添加積分:插入語句
class ScoreDAO:訪問數據庫—用戶信息:查詢語句
class DbUtil:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Login.DAL
{
class DbUtil//用於保存 鏈接服務器的SQL語句
{
public static string ConnString = @"Server=DESKTOP-4LVQ49K;Database=Login;uid=sa;Password=123456";
}
}
提個問題:D 層中的這個DbUtil類有什麼用?爲什麼要單獨寫成一個類?
答:大家不難發現:這個類只是實現了一個連接數據庫的功能,但是這個連接數據庫的語句很長,並且在UserDAO類和ScoreDAO類中都需要連接數據庫,所以在這裏把連接數據庫的語句抽出來,封裝成一個類,用一個string類型的 ConnString 對象接收,之後需要連接數據庫時,只需要調用這個對象就可以了!
class UserDAO:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Login.Model;
using System.Data;
using System.Data.SqlClient;//SqlConnection的命名空間
namespace Login.DAL
{
public class UserDAO//數據訪問層---訪問用戶信息
{
public Login.Model.UserInfo SelectUser(string userName, string password)
{ //using 是爲了自動釋放()裏邊的資源
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))//實例化了一個連接數據庫的對象,類似於一個開數據庫的鑰匙
{
SqlCommand cmd = conn.CreateCommand();//在現有連接conn的基礎上,創建一個命令用以執行SQL指令。
conn.Open();//連接(數據庫的)打開
// CommandText:獲取或設置要在數據源中執行的 Transact-SQL 語句、表名或存儲過程。
cmd.CommandText = @"SELECT ID,UserName,Password,Email FROM USERS WHERE UserName=@UserName AND Password=@Password";//執行的select語句
//CommandType:獲取或設置一個值,該值指示解釋 CommandText 屬性的方式。
cmd.CommandType = CommandType.Text;//CommandType是一個枚舉類型,有三個值:text、StoredProcedure(存儲過程)、TableDirect用於表示SqlCommand對象CommandType的執行形式,這裏是text
//把用戶輸入的內容存到Parameters集合中
cmd.Parameters.Add(new SqlParameter("@UserName", userName));
cmd.Parameters.Add(new SqlParameter ("@Password",password ));
SqlDataReader reader = cmd.ExecuteReader();//ExecuteReader :儘可能快地對數據庫進行查詢並得到結果。
//聲明一個Login.Model.UserInfo 類型的對象user,只是聲明
Login.Model.UserInfo user = null;
while (reader.Read())//把數據庫中讀到的信息給user對象,返回給B層
{
if (user == null)
{
user = new Login.Model.UserInfo();//實例化user
}
user.Id = reader.GetInt32(0);
user.UserName = reader.GetString(1);
user.Password = reader.GetString(2);//not suggestion
if (!reader.IsDBNull(3))
{
user.Email = reader.GetString(3);
}
}
return user;
}
}
}
}
class ScoreDAO:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
namespace Login.DAL
{
public class ScoreDAO
{
public void UpdateScore(string userName, int value)
{
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))
{
SqlCommand cmd = conn.CreateCommand();
conn.Open();
cmd.CommandText = @"INSERT INTO SCORES(UserName,Score) Values(@UserName,@Score)";//插入積分
//把用戶輸入的內容存到Parameters集合中
cmd.Parameters.Add(new SqlParameter("@UserName", userName));
cmd.Parameters.Add(new SqlParameter("@Score", value));
//SqlCommand.ExecuteNonQuery()方法:對連接執行SQL語句並返回受影響的行數。
cmd.ExecuteNonQuery();
}
}
}
}
提個問題三個問題:
✦問題一:using(){}的用法:
using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))
{
...
}
對於這個問題的詳細解釋,請看小編的下篇博客:
https://blog.csdn.net/Ginny97/article/details/103943672
✦問題二:System.data和System.Data.Sqlclient命名空間:
System.data:即表示你的命名空間下有需要使用數據、數組的地方,可以直接使用數組類型,而不需要再添加前綴。
最常見的地方應該是ADO.NET數據層(即操作數據庫的類)
System.Data.Sqlclient:表示在你的代碼中引入微軟發佈的sqlserver數據庫的ado.net程序集,引入後,你就可以使用SqlConnection、SqlCommand等數據庫對象來訪問sqlserver數據庫。
✦問題三:關於cmd.Parameters.Add()的理解:
SqlParameter是什麼:它表示SqlCommand的參數,以及可選的到DataSet列的映射。這個類不能被繼承。(SqlCommand:表示要針對SQL Server數據庫執行的Transact-SQL語句或存儲過程。這個類不能被繼承。DataSet:表示內存中的數據緩存。)
具體的作用和使用,可以參照這位博主的博客:感謝她的分享,也讓小編學習到了:https://blog.csdn.net/hsm_Jasmine/article/details/103339498