新手學C# ——.net的三層架構之最簡單實例:登陸界面sql
三層架構包括:數據庫
1. 數據訪問層(Data Access Layer, DAL):負責將底層數據傳送到業務邏輯層架構
2. 業務邏輯層(Business Logic Layer, BLL):處理數據訪問層傳送的數據,並實現業務邏輯函數
3. 表示層(User Interface, UI):不處理任何業務,負責顯示與實時更新學習
其中1--2--3層次依次上升。this
爲了使信息可以順利由底層傳送,能夠採用實體類的方法,添加實體層。實體類一般與數據庫中字段相互對應,擁有get和set屬性。實體類的目的是用於替代DataSet,經過類的方式傳遞數據,並使邏輯更加清晰。spa
三層架構來源於MVC,其核心思想是保持三層之間的相互獨立,在對其餘功能進行局部修改時,可使三層結構保持大致不變,以避免進行全局的修改。換句話說,在修改某局部代碼後,你天然而然的知道何處的代碼應該進行修改,何處的代碼能夠不進行修改,如何規範修改的局部代碼對上層的接口以達到減小修改量的目的。.net
這裏不得不說的是,在三層架構中,修改局部代碼對總體的變更仍是很大的,層次數越多,須要修改的部分越少。固然,層次數的增長伴隨着邏輯的複雜性增長和接口的複雜性增長。越是小型的項目,須要的層次數越少。code
下面舉一個最簡單的例子:用戶登陸。orm
數據庫中表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學習的菜鳥級新手有所幫助!(本人也處於這一行列)