- [SQLSERVER] Loại bỏ Restricted User trên database MSSQL
- [C#] Hướng dẫn tạo mã QRcode Style trên winform
- [C#] Hướng dẫn sử dụng temp mail service api trên winform
- [C#] Hướng dẫn tạo mã thanh toán VietQR Pay không sử dụng API trên winform
- [C#] Hướng Dẫn Tạo Windows Service Đơn Giản Bằng Topshelf
- [C#] Chia sẻ source code đọc dữ liệu từ Google Sheet trên winform
- [C#] Chia sẻ source code tạo mã QR MOMO đa năng Winform
- [C#] Chia sẻ source code phần mềm lên lịch tự động chạy ứng dụng Scheduler Task Winform
- [Phần mềm] Tải và cài đặt phần mềm Sublime Text 4180 full version
- [C#] Hướng dẫn download file từ Minio Server Winform
- [C#] Hướng dẫn đăng nhập zalo login sử dụng API v4 trên winform
- [SOFTWARE] Phần mềm gởi tin nhắn Zalo Marketing Pro giá rẻ mềm nhất thị trường
- [C#] Việt hóa Text Button trên MessageBox Dialog Winform
- [DEVEXPRESS] Chia sẻ code các tạo report in nhiều hóa đơn trên XtraReport C#
- [POWER AUTOMATE] Hướng dẫn gởi tin nhắn zalo từ file Excel - No code
- [C#] Chia sẻ code lock và unlock user trong domain Window
- [DEVEXPRESS] Vẽ Biểu Đồ Stock Chứng Khoán - Công Cụ Thiết Yếu Cho Nhà Đầu Tư trên Winform
- [C#] Hướng dẫn bảo mật ứng dụng 2FA (Multi-factor Authentication) trên Winform
- [C#] Hướng dẫn convert HTML code sang PDF File trên NetCore 7 Winform
- [C#] Hướng dẫn viết ứng dụng chat với Gemini AI Google Winform
[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:
- Giới thiệu về mô hình 3 lớp.
- Cách tạo project và liên kết 3 lớp.
- Xây dựng DTO
- Xây dựng Data Access
- Xây dựng Business (BUS)
- Xây dựng GUI
- 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:
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 và DTO.
- Business Layer liên kết tới được Data Access và 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é
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é.
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
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:
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:
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 và 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é):
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.
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
Laptrinhvb via sethphat.com