[C#] Hướng Dẫn Lập Trình Mô Hình Ba Lớp Three Layer Trong Csharp

Đối với lập trình hiện đại, mọi thứ đều đi nhiều lớp, tương tự như C#, cũng có cả mô hình 3 lớp C# để chúng ta thực thi áp dụng.

Ở C# chúng ta gọi là mô hình 3 lớp aka 3 Layers. Nó khá là nổi tiếng với sinh viên VN đang học C# (một số trường sẽ là Lập trình .NET, lập trình C#, lập trình ứng dụng).

Mục lục:

  1. Giới thiệu về mô hình 3 lớp.
  2. Cách tạo project và liên kết 3 lớp.
  3. Xây dựng DTO
  4. Xây dựng Data Access
  5. Xây dựng Business (BUS)
  6. Xây dựng GUI
  7. Lời kết và Source Code mẫu

Cấu tạo của C# – Mô hình 3 lớp đơn giản:

Gồm 3 lớp, đó là:

  • GUI Layer: Lớp này là lớp hiển thị giao diện và các chức năng để người dùng cuối sử dụng.
  • Business (BUS) Layer: Đây là lớp nhận các yêu cầu từ lớp GUI và truy xuất lên lớp Data để lấy thông tin và trả về GUI.
  • Data Access Layer: Lớp này là lớp để truy xuất với CSDL, chỉ duy nhất lớp này được làm việc với database.
  • (Ko cần thiết) DTO Layer: Lớp này chỉ là phụ thôi, đây là lớp định nghĩa các table trong database của bạn, định nghĩa cột của nó cũng như để ta gán data khi query lấy dữ liệu. Các bạn có thể hiểu nôm na là 1 dạng cơ bản ORM (Object Relation Mapping).

Đây là cách hoạt động của mô hình 3 lớp:

3layers

Nhìn sơ qua thì nó khá là giống MVC bên web nhỉ? Business như là Controller :D, GUI là View và Data Access là Model.

Lợi thế của mô hình 3 lớp:

  • Phân loại rõ ràng các lớp có các nhiệm vụ khác nhau. Từ đó ta có thể quản lý và maintain project tốt hơn.
  • Dễ dàng phân loại các hành động tại Business.
  • Dễ dàng phân loại các hàm truy xuất tại Database, phân loại hàm theo table,…
  • Ứng dụng được cho các project lớn ở bên ngoài.

Lưu ý khi xây dựng mô hình 3 lớp:

  • Cần một solution riêng cho project.
  • Cần 3 project khác nhau để làm nên 3 lớp, tên Project đặt như sau:
    • Lớp GUI: GUI_* (VD: GUI_QuanLy)
    • Lớp Business: BUS_* (VD: BUS_QuanLy)
    • Lớp Data Access: DAL_* (VD: DAL_QuanLy)
    • Lớp DTO: DTO_* (VD: DTO_QuanLy)
  • Bên trong 3 lớp như trên các file đặt cần có các tiền tố như sau:Ví dụ mình có một table tên là ThanhVien

     

    • Lớp GUI: GUI_* (VD: GUI_ThanhVien)
    • Lớp Business: BUS_* (VD: GUI_ThanhVien)
    • Lớp Data Access: DAL_* (VD: GUI_ThanhVien)
    • Lớp DTO: DTO_* (VD: DTO_ThanhVien)

Như các bạn đã thấy tên Table liên quan mật thiết tới cách đặt tên file nhé 

C# – Mô hình 3 lớp đơn giản: Liên kết 3 lớp

Như các bạn đã nhìn tại sơ đồ ở trang 1 thì Mô hình 3 lớp hoạt động như sau:

  • GUI liên kết tới dc Business Layer  DTO.
  • Business Layer liên kết tới được Data Access  DTO.
  • Data Access chỉ liên kết tới DTO.

Bây giờ chúng ta bắt đầu tạo, đối với 3 Project DTO, Business và Data Access chúng ta tạo theo Class Library nhé

dto

Và khi tạo xong, ta sẽ có 4 project như sau(Có mấy file class1.cs xóa thoải mái nhé.

4pro

Và bây giờ chúng ta sẽ liên kết, làm project GUI trước nhé. Đầu tiên ta chọn chuột fải vào References => Add Reference

x2q

Một cái bảng hiện ra, tại mục Project ta sẽ chọn 2 lớp mà lớp GUI có thể liên kết tới là BUS và DTO:

asdasd123-768x534

Cứ OK là Reference sẽ được thêm vào GUI, chúng ta có thể kiểm tra bằng cách mở References ra:

asdzzz

Như bên hình thì mình đã thêm thành công, và các bạn làm tương tự đối với BUS  DAL theo mình nói bên trên nhé.

Thế là bạn đã liên kết xong cho mô hình 3 lớp. 

C# – Mô hình 3 lớp đơn giản – Xây dựng mô hình 3 lớp: Xây dựng DTO

Cơ sở dữ liệu:

CSDL mình sẽ xài table ThanhVien như sau:

CREATE TABLE THANHVIEN ( TV_ID INT NOT NULL PRIMARY KEY IDENTITY, TV_NAME NVARCHAR(30) NOT NULL, TV_PHONE VARCHAR(11) NOT NULL, TV_EMAIL VARCHAR(50) NOT NULL )

Xây dựng DTO

Mình sẽ tạo file DTO_ThanhVien.cs (Class file), về cơ bản thì các cột của table ThanhVien của mình ra sao thì mình tạo 1 class y hệt vậy kèm get/set và 2 hàm khởi tạo.

DTO_ThanhVien.cs

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DTO_QuanLy { public class DTO_ThanhVien { private int _THANHVIEN_ID; private string _THANHVIEN_NAME; private string _THANHVIEN_PHONE; private string _THANHVIEN_EMAIL; /* ======== GETTER/SETTER ======== */ public int THANHVIEN_ID { get { return _THANHVIEN_ID; } set { _THANHVIEN_ID = value; } } public string THANHVIEN_NAME { get { return _THANHVIEN_NAME; } set { _THANHVIEN_NAME = value; } } public string THANHVIEN_PHONE { get { return _THANHVIEN_PHONE; } set { _THANHVIEN_PHONE = value; } } public string THANHVIEN_EMAIL { get { return _THANHVIEN_EMAIL; } set { _THANHVIEN_EMAIL = value; } } /* === Constructor === */ public DTO_ThanhVien() { } public DTO_ThanhVien(int id, string name, string phone, string email) { this.THANHVIEN_ID = id; this.THANHVIEN_EMAIL = email; this.THANHVIEN_NAME = name; this.THANHVIEN_PHONE = phone; } } }

C# – Mô hình 3 lớp đơn giản – Xây dựng mô hình 3 lớp: Xây dựng Data Access

Tại sao mình lại xây dựng Data Access trước? Đơn giản là đây là lớp mà ta xử lý bên database, làm trước thì design GUI xong chỉ việc bỏ vào sử dụng thôi.

Điều quan trọng đầu tiên, chúng ta cần tạo class DBConnect.cs với nội dung như sau:

using System.Data.SqlClient; namespace DAL_QuanLy { public class DBConnect { protected SqlConnection _conn = new SqlConnection("Data Source=ADMINISTRATORSQLEXPRESS;Initial Catalog=ThanhVien;Integrated Security=True"); } }

Chúng ta sẽ tạo SqlConnection và khởi tạo luôn, sau này các class DAL chúng ta chỉ cần kế thừa class DBConnect là có thể sử dụng _conn thoải mái ko cần khởi tạo lại.

Các bạn nhớ sửa lại connection string cho chuẩn bên máy của các bạn nhé. Ở đây vì bài tập đơn giản nên ta chịu khó hard-code vậy :D. Chúng ta có nhiều cách khác nhau để tránh hard-code nhưng mình sẽ nói sau ở các bài khác.

Mình sẽ tạo file DAL_ThanhVien.cs (Class file)

Ở đây mình sẽ làm sẵn luôn 4 methods là: Lấy tất cả, Thêm, Xóa, Sửa nhé 

DAL_ThanhVien.cs:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Data.SqlClient; using DTO_QuanLy; namespace DAL_QuanLy { public class DAL_ThanhVien : DBConnect { /// <summary> /// Get toàn bộ thành viên /// </summary> /// <returns></returns> public DataTable getThanhVien() { SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM THANHVIEN", _conn); DataTable dtThanhvien = new DataTable(); da.Fill(dtThanhvien); return dtThanhvien; } /// <summary> /// Thêm thành viên /// </summary> /// <param name="tv"></param> /// <returns></returns> public bool themThanhVien(DTO_ThanhVien tv) { try { // Ket noi _conn.Open(); // Query string - vì mình để TV_ID là identity (giá trị tự tăng dần) nên ko cần fải insert ID string SQL = string.Format("INSERT INTO THANHVIEN(TV_NAME, TV_PHONE, TV_EMAIL) VALUES ('{0}', '{1}', '{2}')", tv.THANHVIEN_NAME, tv.THANHVIEN_PHONE, tv.THANHVIEN_EMAIL); // Command (mặc định command type = text nên chúng ta khỏi fải làm gì nhiều). SqlCommand cmd = new SqlCommand(SQL, _conn); // Query và kiểm tra if (cmd.ExecuteNonQuery() > 0) return true; } catch (Exception e) { } finally { // Dong ket noi _conn.Close(); } return false; } /// <summary> /// Sửa thành viên /// </summary> /// <param name="tv"></param> /// <returns></returns> public bool suaThanhVien(DTO_ThanhVien tv) { try { // Ket noi _conn.Open(); // Query string string SQL = string.Format("UPDATE THANHVIEN SET TV_NAME = '{0}', TV_PHONE = '{1}', TV_EMAIL = '{2}' WHERE TV_ID = {3}", tv.THANHVIEN_NAME, tv.THANHVIEN_PHONE, tv.THANHVIEN_EMAIL, tv.THANHVIEN_ID); // Command (mặc định command type = text nên chúng ta khỏi fải làm gì nhiều). SqlCommand cmd = new SqlCommand(SQL, _conn); // Query và kiểm tra if (cmd.ExecuteNonQuery() > 0) return true; } catch (Exception e) { } finally { // Dong ket noi _conn.Close(); } return false; } /// <summary> /// Xóa thành viên /// </summary> /// <param name="tv"></param> /// <returns></returns> public bool xoaThanhVien(int TV_ID) { try { // Ket noi _conn.Open(); // Query string - vì xóa chỉ cần ID nên chúng ta ko cần 1 DTO, ID là đủ string SQL = string.Format("DELETE FROM THANHVIEN WHERE TV_ID = {0})", TV_ID); // Command (mặc định command type = text nên chúng ta khỏi fải làm gì nhiều). SqlCommand cmd = new SqlCommand(SQL, _conn); // Query và kiểm tra if (cmd.ExecuteNonQuery() > 0) return true; } catch (Exception e) { } finally { // Dong ket noi _conn.Close(); } return false; } } }

C# – Mô hình 3 lớp đơn giản – Xây dựng mô hình 3 lớp: Xây dựng Business

Bước này là bước xử lý business logic (Business layer).

Ở bước này, ta có thể lấy dữ liệu từ DAL về, xử lý ABC XYZ gì đó rồi trả về lại cho GUI sử dụng. Hoặc khi update dữ liệu trên DB, GUI gửi data lên BUS và rồi ta xử lý ABC XYZ gì đó cho data của chúng ta, rồi mới insert/update/delete chẳng hạn,…

Vì app mình build là app đơn giản, nên mình chỉ cần gọi lên DAL và trả về tương ứng cho GUI xài thui 

Mình sẽ tạo BUS_ThanhVien.cs (Class file):

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using DAL_QuanLy; using DTO_QuanLy; namespace BUS_QuanLy { public class BUS_ThanhVien { DAL_ThanhVien dalThanhVien = new DAL_ThanhVien(); public DataTable getThanhVien() { return dalThanhVien.getThanhVien(); } public bool themThanhVien(DTO_ThanhVien tv) { return dalThanhVien.themThanhVien(tv); } public bool suaThanhVien(DTO_ThanhVien tv) { return dalThanhVien.suaThanhVien(tv); } public bool xoaThanhVien(int TV_ID) { return dalThanhVien.xoaThanhVien(TV_ID); } } }

Chỉ đơn giản là gọi hàm và trả về thôi (app đơn giản mà @@)

C# – Mô hình 3 lớp đơn giản – Xây dựng mô hình 3 lớp: Xây dựng GUI

Về GUI thì mình sẽ design như sau (mình sẽ gửi source đầy đủ ở trang cuối nhé):

formX

Và mình sẽ gán lần lượt các chức năng vào nhé:

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 DTO_QuanLy; using BUS_QuanLy; namespace GUI_QuanLy { public partial class GUI_ThanhVien : Form { BUS_ThanhVien busTV = new BUS_ThanhVien(); public GUI_ThanhVien() { InitializeComponent(); } private void btnExit_Click(object sender, EventArgs e) { Application.Exit(); } private void btnAdd_Click(object sender, EventArgs e) { if (txtEmail.Text != "" && txtName.Text != "" && txtSDT.Text != "") { // Tạo DTo DTO_ThanhVien tv = new DTO_ThanhVien(0, txtName.Text, txtSDT.Text, txtEmail.Text); // Vì ID tự tăng nên để ID số gì cũng dc // Them if (busTV.themThanhVien(tv)) { MessageBox.Show("Thêm thành công"); dgvTV.DataSource = busTV.getThanhVien(); // refresh datagridview } else { MessageBox.Show("Thêm ko thành công"); } } else { MessageBox.Show("Xin hãy nhập đầy đủ"); } } private void GUI_ThanhVien_Load(object sender, EventArgs e) { dgvTV.DataSource = busTV.getThanhVien(); // get thanh vien } private void btnEdit_Click(object sender, EventArgs e) { // Kiểm tra nếu có chọn table rồi if (dgvTV.SelectedRows.Count > 0) { if (txtEmail.Text != "" && txtName.Text != "" && txtSDT.Text != "") { // Lấy row hiện tại DataGridViewRow row = dgvTV.SelectedRows[0]; int ID = Convert.ToInt16(row.Cells[0].Value.ToString()); // Tạo DTo DTO_ThanhVien tv = new DTO_ThanhVien(ID, txtName.Text, txtSDT.Text, txtEmail.Text); // Vì ID tự tăng nên để ID số gì cũng dc // Sửa if (busTV.suaThanhVien(tv)) { MessageBox.Show("Sửa thành công"); dgvTV.DataSource = busTV.getThanhVien(); // refresh datagridview } else { MessageBox.Show("Sửa ko thành công"); } } else { MessageBox.Show("Xin hãy nhập đầy đủ"); } } else { MessageBox.Show("Hãy chọn thành viên muốn sửa"); } } private void dgvTV_Click(object sender, EventArgs e) { // Lấy row hiện tại DataGridViewRow row = dgvTV.SelectedRows[0]; // Chuyển giá trị lên form txtName.Text = row.Cells[1].Value.ToString(); txtSDT.Text = row.Cells[2].Value.ToString(); txtEmail.Text = row.Cells[3].Value.ToString(); } private void btnDelete_Click(object sender, EventArgs e) { // Kiểm tra nếu có chọn table rồi if (dgvTV.SelectedRows.Count > 0) { // Lấy row hiện tại DataGridViewRow row = dgvTV.SelectedRows[0]; int ID = Convert.ToInt16(row.Cells[0].Value.ToString()); // Xóa if (busTV.xoaThanhVien(ID)) { MessageBox.Show("Xóa thành công"); dgvTV.DataSource = busTV.getThanhVien(); // refresh datagridview } else { MessageBox.Show("Xóa ko thành công"); } } else { MessageBox.Show("Hãy chọn thành viên muốn xóa"); } } } }

Xây dựng mô hình 3 lớp: Lời kết + source files

Sau khi viết xong thì toàn bộ chương trình demo của mình.

texa

Mô hình 3 lớp có lợi và hại hết nhưng hầu như lợi nhiều hơn đấy các bạn.

Mô hình 3 lớp tại C# khá là phổ biến từ trước tới nay nên học nó sẽ ko dư hay thiếu đâu.

 

Xem thêm cách thiết kế ứng dụng theo mô hình MVP

DOWNLOAD SOURCE

Laptrinhvb via sethphat.com

Tags: 3 layer c#ba lớp c#design patternmvp pattern

Từ khóa » Thêm Xóa Sửa Trong C# Mô Hình 3 Lớp