• Vui lòng đọc nội qui diễn đàn để tránh bị xóa bài viết
  • Tìm kiếm trước khi đặt câu hỏi

Kiểm tra dữ liệu trước khi lưu trong .NET

Các bài viết hướng dẫn về Visual Basic .NET và C#

Điều hành viên: tungcan5diop, QUANITGROBEST

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 346
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 79 time

Kiểm tra dữ liệu trước khi lưu trong .NET

Gửi bàigửi bởi thuongbat » T.Sáu 08/07/2011 12:40 pm

Tên bài viết: Kiểm tra dữ liệu trước khi lưu trong .NET
Tác giả: ThuongBat
Cấp độ bài viết: Trung bình
Tóm tắt: Một cách mới để kiểm tra dữ liệu hợp lệ trước khi lưu vào database



1. Đặt vấn đề:

Trước khi lưu dữ liệu người dùng nhập trên Form vào database, bao giờ bạn cũng có một bước kiểm tra sự hợp lệ của dữ liệu. Nếu dữ liệu không hợp lệ, bạn phải thông báo cho người dùng biết: chỗ nào chưa hợp lệ, tại sao nó chưa hợp lệ để người dùng nhập lại. Đây chính là mục đích của bài viết này.

2. Một số cách tiếp cận:

a. Cách truyền thống:
Bạn kiểm tra từng control trên form (textbox, combobox, datetimepicker....). Nếu ô nào không hợp lệ, bạn thông báo với người dùng và Focus() vào control đó
Ví dụ:
  1. if(txtCustomer.TextLength==0)
  2. {
  3. MessageBox.Show("Chưa nhập tên khách hàng");
  4. txtCustomer.Focus();
  5. return;
  6. }
  7.  

Cách này có cái hay là bạn thông báo được chi tiết trường dữ liệu nào chưa hợp lệ, vì sao nó chưa hợp lệ. Nhưng có một cái dở là: nếu bạn có một Form thêm khách hàng, một Form sửa khách hàng thì code kiểm tra bạn phải viết trên cả 2 form. Hơn nữa, nếu số trường dữ liệu của bạn nhiều thì việc gõ đi gõ lại những đoạn code như trên sẽ khá nhàm chán.
b. Cách này cũng truyền thống, nhưng có cải tiến hơn 1 chút:
Bạn dùng vòng For để lặp tất cả các control trên Form. Gặp Control nào thỏa mãn điều kiện (ví dụ: gặp Textbox) thì bạn kiểm tra dữ liệu của control đó. Rồi thông báo lỗi nếu có
Ví dụ
  1. foreach(Control ctl in this.Controls)
  2. {
  3. if (ctl is Textbox)
  4. {
  5. //kiểm tra dữ liệu
  6. //thông báo lỗi nếu có
  7. }
  8. }
  9.  

Cách này khá nhàn khi viết, nhưng nhược điểm của nó là: nếu control nhập liệu bạn đặt trong control khác (ví dụ: groupbox) thì vòng for lại không có hiệu lực. Hơn nữa, vì dùng chung một vòng lặp kiểm tra nên việc kiểm tra hợp lệ cho từng trường dữ liêu sẽ không được chi tiết. Bạn chỉ có thể kiểm tra các điều kiện chung chung như: textbox rỗng hay không? datetime hợp lệ hay không? Và câu thông báo khi dữ liệu không hợp lệ lại càng không được chi tiết
c. Cách kiểm tra mới: đây là cách mà tôi dự định viết ra sau đây. Đó là cách cho các đối tượng tự kiểm tra dữ liệu của chính nó. Chương trình của bạn có thể có các đối tượng như: Khách hàng, Người dùng,..... Cách này sẽ cho các đối tượng tự kiểm tra các thuộc tính của chính nó. Bạn sẽ không cần tí code kiểm tra nào trong Form nữa. Chi tiết, vui lòng đọc tiếp phía dưới nhé

3. Yêu cầu cần có:
+ Chương trình của bạn phải có các đối tượng tương ứng với dữ liệu cần nhập. Ví dụ: nếu bạn có bảng Khách hàng ở trong CSDL, thì bạn phải có đối tượng Khách hàng trong project của mình. Nếu bạn lập trình theo kiểu đọc từ CSDL ra Datatable, rồi từ Datatable gán thẳng lên Form (và ngược lại khi lưu dữ liệu, bạn gán thẳng Textbox.Text vào câu SQL) thì bạn không cần phải xem tiếp cách phần phía sau vì nó không giúp gì cho chương trình của bạn đâu
+ Bạn cần có thêm thư viện Microsoft.Practices.EnterpriseLibrary.Validation. Thư viện này là của Microsoft phát triển. Trong Visual Studio mặc định hình như là không có (mình tìm hoài không thấy). Nhưng mình đã down được nó ở trên internet và sẽ sẽ gửi kèm trong bài viết này.

4. Cùng thực hiện nào:
a. Tạo Project:
- Bạn tạo một Project mới kiểu WinForm nhé
- Add Reference đến thư viện Microsoft.Practices.EnterpriseLibrary.Validation.dll (tải tệp đính kèm của bài viết để có thư viện này)
b. Tạo đối tượng nhập liệu: ở đây tôi tạo một đối tượng ví dụ là đối tượng khách hàng. Code như sau:
  1. public class Customer
  2.     {
  3.         public int Id { get; set; }
  4.         private string customername;
  5.         public string CustomerName
  6.         {
  7.             get { return customername; }
  8.             set { customername = value; }
  9.         }
  10.         private string email;
  11.         public string Email
  12.         {
  13.             get { return email; }
  14.             set { email = value; }
  15.         }
  16.     }
  17.  

Đối tượng khách hàng này có 3 thuộc tính: Id, CustomerName và Email. Trong đó có 2 thuộc tính cần kiểm tra hợp lệ là:
+ CustomerName: Độ dài cho phép từ 5 đến 50 ký tự
+ Email: phải là địa chỉ email hợp lệ (dạng: abc@examplesite.com)
c. Tạo các ràng buộc cho đối tượng này: Chi tiết, tôi mô tả luôn trong Comment của code:
  1. //2 namespace này có trong thư viện đã Add Reference ở bước 4.a
  2. //trong 2 thư viện đó, có những class và Attribute cần thiết để ta
  3. //tạo ràng buộc cho Class
  4. using Microsoft.Practices.EnterpriseLibrary.Validation;
  5. using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
  6.  
  7. namespace WindowsFormsApplication1
  8. {
  9.     public class Customer
  10.     {
  11.         public int Id { get; set; }
  12.         private string customername;
  13.         //StringLengthValidator sẽ giúp ta kiểm tra xem CustomerName có hợp lệ hay không
  14.         //Tham số tôi đã sử dụng: 5=> độ dài tối thiểu; 50=> độ dài tối đa;
  15.         //MessageTemplate: nội dung thông báo lỗi nếu dữ liệu không hợp lệ
  16.         [StringLengthValidator(5,50, MessageTemplate="Tên khách hàng phải có độ dài từ 5 đến 50 ký tự")]
  17.         public string CustomerName
  18.         {
  19.             get { return customername; }
  20.             set { customername = value; }
  21.         }
  22.         private string email;
  23.         //RegXValidator giúp ta kiểm tra email có hợp lệ hay không
  24.         //tham số thứ nhất: Pattern để so sánh
  25.         //tham số thứ 2: nội dung thông báo lỗi
  26.         //nguyên tắc: Email sẽ được đem ra so sánh với Pattern theo quy luật của Regular Expression
  27.         //nếu Email không trùng với Pattern thì sẽ thông báo lỗi
  28.         //có nhiều Pattern có thể kiểm tra email. Bạn có thể sử dụng Pattern khác nếu muốn
  29.         [RegexValidator(@"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$", MessageTemplate = "Địa chỉ email bạn đã nhập không hợp lệ")]
  30.         public string Email
  31.         {
  32.             get { return email; }
  33.             set { email = value; }
  34.         }
  35.     }
  36. }
  37.  


d. Thiết kế Form nhập liệu:
Form nhập liệu tôi làm đơn giản thôi. Có 2 textbox để nhập CustomerName và Email, một Button để người dùng click vào đó thì sẽ bắt đầu lưu
form1.png
form1.png (6.09 KiB) Đã xem 7232 lần


e. Code cho Form nào:
[csharp]using System;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Customer cust = null; //khai báo đối tượng Customer để chứa dữ liệu
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//khởi tạo đối tượng Customer
cust = new Customer();
//bind CustomerName vào txtCustomerName
txtCustomerName.DataBindings.Add("Text", cust, "CustomerName");
//bind Email và txtEmail
txtEmail.DataBindings.Add("Text", cust, "Email");
//tôi dùng phương pháp Bind thuộc tính của lớp Customer vào Textbox
//để khi người sử dụng nhập liệu vào Textbox thì biến cust của tôi
//được cập nhật luôn, không phải gán qua gán lại kiểu như cust.CustomerName=txtCustomerName.Text
}
}
}

[/csharp]

f. Kiểm tra tính hợp lệ của dữ liệu:
Bây giờ, khi người dùng nhấn vào nút Lưu, tôi phải kiểm tra tính hợp lệ của các dữ liệu đã nhập vào. Tôi viết code cho nút Lưu như sau:
[csharp]
//bạn using 2 Namespace này ở đầu Form để có các lớp cần thiết cho việc xử lý nhé
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
private void btnSave_Click(object sender, EventArgs e)
{

ValidationResults results = null; //biến này để nhận các thông báo lỗi trả về
results = Validation.Validate<Customer>(cust); //lớp Validation có hàm Static là Validate<T> để kiểm tra dữ liệu
if (results.IsValid)
{
//thông tin hợp lệ => lưu dữ liệu
MessageBox.Show("Dữ liệu bạn nhập đã hợp lệ");
//lưu dữ liệu vào DB ở đây
}
else
{
//thông tin không hợp lệ
string errMessage = string.Empty; //build chuỗi Error Message
foreach (ValidationResult result in results)
{
errMessage += result.Message + "\r\n";
}
MessageBox.Show(errMessage);
}
}[/csharp]


Đã xong. Bây giờ bạn chạy chương trình. Nhấn nút Lưu và bạn sẽ thấy kết quả
error.png
error.png (40.24 KiB) Đã xem 7232 lần

Bạn nhập dữ liệu cho các textbox hợp lệ, nhấn nút lưu lần nữa, và kết quả là:
correct.png
correct.png (38.63 KiB) Đã xem 7232 lần


5. Mở rộng:
a. Trường dữ liệu không bắt buộc nhập:
Trong ví dụ trên, tôi đã bắt buộc cả CustomerName và Email đều phải có dữ liệu. Bây giờ tôi muốn thay đổi, Email của tôi là không bắt buộc phải nhập. Nhưng nếu đã nhập thì phải nhập email chính xác. Vậy tôi làm thế nào? Tôi sẽ thay đổi lớp Customer của tôi như sau:
[csharp]
//2 namespace này có trong thư viện đã Add Reference ở bước 4.a
//trong 2 thư viện đó, có những class và Attribute cần thiết để ta
//tạo ràng buộc cho Class
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

namespace WindowsFormsApplication1
{
//thêm Attribute này, nó sẽ báo cho .NET runtime biết: đối tượng của ta có
//hàm tự kiểm tra hợp lệ
[HasSelfValidation()]
public class Customer
{
public int Id { get; set; }
private string customername;
//StringLengthValidator sẽ giúp ta kiểm tra xem CustomerName có hợp lệ hay không
//Tham số tôi đã sử dụng: 5=> độ dài tối thiểu; 50=> độ dài tối đa;
//MessageTemplate: nội dung thông báo lỗi nếu dữ liệu không hợp lệ
[StringLengthValidator(5,50, MessageTemplate="Tên khách hàng phải có độ dài từ 5 đến 50 ký tự")]
public string CustomerName
{
get { return customername; }
set { customername = value; }
}
private string email;
//không cần thuộc tính kiểm tra Email ở đây nữa, vì Email là không bắt buộc nhập
//ta sẽ kiểm tra email trong hàm Validate ở dưới
public string Email
{
get { return email; }
set { email = value; }
}

//đây là hàm tự kiểm tra của lớp Customer
//khi bạn gọi Validation.Validate<Customer>(cust) ở Form1, hàm này
//sẽ được tự động gọi
[SelfValidation()]
public void Validate(ValidationResults results)
{
if ((email!=null) && (email.Length > 0)) //tôi chỉ kiểm tra email có hợp lệ hay không nếu người dùng có nhập Email
{
//tạo đối tượng RegxValidator để kiểm tra email
RegexValidator regxValidator = new RegexValidator(@"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$");
regxValidator.MessageTemplate = "Email bạn nhập không hợp lệ";
//kiểm tra tính hợp lệ của email
ValidationResults emailResults = regxValidator.Validate(email);
if (!emailResults.IsValid)//nếu email không hợp lệ -> đưa kết quả lỗi ra để xử lý
{
//tất cả các kết quả mà bạn add vào results sẽ được đưa ra cùng với
//kết quả của lời gọi Validation.Validate<Customer>(cust) ở Form1
results.AddAllResults(emailResults);
}
}
}
}
}

[/csharp]

Với cách viết hàm tự kiểm tra cho lớp, bạn có thể làm được rất nhiều việc. Như trên, tôi đã áp dụng để kiểm tra sự hợp lệ của trường dữ liệu không bắt buộc nhập. Bạn cũng có thể áp dụng để kiểm tra 2 thuộc tính ràng buộc lẫn nhau. Tôi ví dụ: nếu tôi có một lớp Nhân Viên trong đó có 2 trường là "Ngày sinh" và "Ngày vào công ty" đều có kiểu DateTime. Hiển nhiên, ngày sinh phải nhỏ hơn ngày vào công ty. Bạn có thể tự viết code kiểm tra trong hàm Validate() để người dùng không nhập nhầm 2 dữ liệu này
Cách viết hàm tự kiểm tra như trên chỉ mang tính chất ví dụ. Đối với thuộc tính không bắt buộc nhập như Email, có một cách nhanh hơn là bạn thêm cho nó thuộc tính [IgnoreNulls()] vào trước thuộc tính [RegxValidator]

Ngoài việc kiểm tra độ dài chuỗi, kiểm tra chuỗi bằng RegxValidator, thư viện Validator của Microsoft còn khá nhiều thuộc tính kiểm tra nữa, các bạn có thể tham khảo tại: http://msdn.microsoft.com/en-us/library ... ators.aspx

Nếu các hàm kiểm tra sẵn có của nó không thỏa mãn nhu cầu của bạn, bạn có thể kế thừa các Validators sẵn có của nó để tạo ra các Validators cho riêng mình. Phần này, nếu có thời gian mình sẽ viết bổ sung


Ví dụ mẫu ở dưới đây nhé. Mọi người down về xem thử
Tập tin đính kèm
WindowsFormsApplication1.rar
(170.17 KiB) Đã tải 1051 lần


Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

Hình đại diện của người dùng
thuongbat
Guru
Guru
Bài viết: 346
Ngày tham gia: CN 27/04/2008 10:11 am
Has thanked: 4 time
Been thanked: 79 time

Kiểm tra dữ liệu trước khi lưu trong .NET (tiếp theo)

Gửi bàigửi bởi thuongbat » T.Bảy 09/07/2011 12:29 pm

b. Kiểm tra chéo
Việc áp dụng các Attributes kiểm tra dữ liệu vào các Properties của lớp chỉ cho phép bạn kiểm tra sự hợp lệ của một Property. Đôi khi, bạn muốn thuộc tính này của đối tượng phải chịu sự ràng buộc của thuộc tính kia. Ví dụ: tôi có một lớp Nhân viên. Lớp nhân viên có nhiều thuộc tính nhưng tôi chỉ xét đến 2 thuộc tính là: Ngày sinh và Ngày vào công ty. Nguyên tắc tôi đặt ra là: nhân viên phải đủ 18 tuổi khi vào công ty. Như vậy, thuộc tính Ngày vào công ty và ngày sinh có sự ràng buộc lẫn nhau. Tôi thực hiện kiểm tra như sau:
  1. using System;
  2. using Microsoft.Practices.EnterpriseLibrary.Validation;
  3. using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
  4. namespace WindowsFormsApplication1
  5. {
  6.     [HasSelfValidation()]
  7.     public class NhanVien
  8.     {
  9.         #region
  10.         //các thuộc tính khác không xét đến
  11.         #endregion
  12.        
  13.         public DateTime NgaySinh{get;set;}
  14.         public DateTime NgayVaoCongTy { get; set; }
  15.  
  16.         [SelfValidation()]
  17.         public void Validate(ValidationResults results)
  18.         {
  19.             if (NgaySinh.AddYears(18) > NgayVaoCongTy)
  20.             {                
  21.                 ValidationResult result = new ValidationResult("Nhân viên chưa đủ 18 tuổi khi vào công ty. Kiểm tra lại ngày sinh và ngày vào công ty", this, "saingaythang", null, null);
  22.                 results.AddResult(result);
  23.             }
  24.         }
  25.     }
  26. }
  27.  
  28.  


c. Kiểm tra ngày tháng
Ở bước b, tôi đã kiểm tra xem ngày sinh và ngày vào công ty có cách nhau 18 năm hay không. Nhưng kiểm tra như vậy chưa xác nhận được là nhân viên đã đủ 18 tuổi. Ví dụ: người dùng nhập ngày sinh là 8/7/2011 và ngày vào cty là: 1/7/2050 thì sao? Rõ ràng là 2 dữ liệu này vượt qua được hàm kiểm tra ở trên (nhưng thực tế là người nhân viên này vừa mới được sinh ra ngày hôm qua). Vậy tôi phải kiểm tra sự hợp lệ của ngày sinh trước. Tôi thêm thuộc tính [RelativeDateTimeValidator] cho lớp nhân viên như sau:
[csharp]
using System;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
namespace WindowsFormsApplication1
{
[HasSelfValidation()]
public class NhanVien
{
#region
//các thuộc tính khác không xét đến
#endregion
// thuộc tính này sẽ so sánh ngày tháng nhập vào với ngày tháng hiện tại của máy
//-60 là giá trị cận dưới cho phép
//-18 là giá trị cận trên cho phép
//DateTimeUnit.Year: so sánh theo năm
//ý nghĩa của đoạn lệnh dưới: Chỉ nhận các giá trị ngày tháng cách thời điểm hiện tại
// gần nhất là 18 năm và xa nhất là 60 năm
[RelativeDateTimeValidator(-60, DateTimeUnit.Year, -18, DateTimeUnit.Year,
MessageTemplate = "Ngày sinh không hợp lệ. Tuổi của nhân viên phải từ 18 đến 60")]
public DateTime NgaySinh{get;set;}
public DateTime NgayVaoCongTy { get; set; }

[SelfValidation()]
public void Validate(ValidationResults results)
{
if (NgaySinh.AddYears(18)> NgayVaoCongTy)
{
ValidationResult result = new ValidationResult("Nhân viên chưa đủ 18 tuổi khi vào công ty. Kiểm tra lại ngày sinh và ngày vào công ty", this, "saingaythang", null, null);
results.AddResult(result);
}
}
}
}
[/csharp]

Dữ liệu nhập thế nào là hợp lệ? Điều đó do chương trình của bạn quyết định chứ không có 1 chuẩn mực nào cả. Hãy luôn luôn sáng tạo trong cuộc sống và trong công việc.
Rượu gặp tri kỷ ngàn chén thiếu.
Chuyện người không hợp nửa câu thừa.

ndt.93qn
Bài viết: 1
Ngày tham gia: T.Sáu 22/11/2013 9:56 pm
Has thanked: 6 time

Re: Kiểm tra dữ liệu trước khi lưu trong .NET

Gửi bàigửi bởi ndt.93qn » CN 20/04/2014 11:32 am

anh ơi, cái này anh có thể viết bằng vb.net được không, em mới tìm hiểu, nên nhìn code à, chứ không hiểu code.


Quay về “[.NET] Bài viết hướng dẫn”

Đang trực tuyến

Đang xem chuyên mục này: Không có thành viên nào trực tuyến.1 khách