Professional Documents
Culture Documents
HCM
227 Nguyễn Văn Cừ - Quận 5- Tp.Hồ Chí Minh
Tel: 8351056 – Fax 8324466 – Email: ttth@hcmuns.edu.vn
MỤC LỤC
GIỚI THIỆU ...........................................................................................................9
GIÁO TRÌNH LÝ THUYẾT......................................................................................10
TÀI LIỆU THAM KHẢO..........................................................................................10
Bài 1.....................................................................................................................11
TỔNG QUAN .NET FRAMEWORK ..........................................................................11
Bài 2.....................................................................................................................34
NGÔN NGỮ VISUAL BASIC .NET ..........................................................................34
VII. Xử lý lỗi..........................................................................................................55
VII.1. Phân loại lỗi ............................................................................................55
VII.2. Xử lý lỗi ..................................................................................................55
Bài 3.....................................................................................................................59
LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG TRONG VISUAL BASIC .NET ............................59
Bài 4.....................................................................................................................78
TỔNG QUAN VỀ ADO.NET ....................................................................................78
I. Tổng quan......................................................................................................79
Bài 5.....................................................................................................................88
CONNECTION, COMMAND, DATAADAPTER .........................................................88
I. Connection.....................................................................................................89
I.1. Data Provider ...............................................................................................89
I.2. ConnectionString ..........................................................................................89
I.3. Các thuộc tính khác của Connection ...............................................................91
I.4. Các phương thức trên Connection ..................................................................91
I.5. Minh họa tạo Connection ...............................................................................91
Bài 6...................................................................................................................105
DATASET, DATATABLE, DATARELATION VÀ DATAVIEW ....................................105
I. DataSet........................................................................................................106
I.1. Khai báo DataSet ........................................................................................ 106
I.2. Các thuộc tính của DataSet.......................................................................... 106
I.3. Các phương thức của DataSet .................................................................... 106
III. DataRelation................................................................................................127
III.1. Khởi tạo ..................................................................................................... 127
III.2. Các thuộc tính của DataRelation................................................................... 128
III.3. Minh họa thiết lập quan hệ .......................................................................... 128
Bài 7...................................................................................................................133
XÂY DỰNG CÁC LỚP XỬ LÝ................................................................................133
Bài 8...................................................................................................................142
THIẾT KẾ CÁC MÀN HÌNH ..................................................................................142
Bài 9...................................................................................................................166
BÁO BIỂU CRYSTAL REPORT .............................................................................166
GIỚI THIỆU
Sau khi hoàn thành khóa học này, học viên sẽ có các khả năng:
Lập trình hướng đối tượng với Visual Basic .Net
Lập trình cơ sở dữ liệu với ADO.Net
Xây dựng ứng dụng với Visual Basic .Net
Với thời lượng là 36 tiết LT và 60 tiết TH được phân bổ như sau:
9 Báo biểu và in ấn 6 10
Tổng số tiết: 36 60
Bài 1
TỔNG QUAN .NET FRAMEWORK
Tóm tắt
Lý thuyết 3 tiết
Giới thiệu các khái niệm cơ bản và 1. Tổng quan .Net Framework
cấu trúc của .Net Framework, đồng 2. Cấu trúc .Net Framework
thời thông qua việc trình bày một
3. Ứng dụng đầu tiên
ứng dụng để giới thiệu về Visual
Studio .Net.
Trong thời đại công nghệ thông tin, dữ liệu trở nên quan trọng đến nỗi người ta mong muốn tất cả mọi
thứ như điện thoại di động, máy tính xách tay, các máy PDA (Personal Digital Assistant) đều phải kết
nối với nhau để chia sẽ dữ liệu và việc sử dụng các phần mềm để quản lý, sử dụng những dữ liệu đó là
"không biên giới". Ứng dụng phải sẵn sàng để sử dụng từ trên máy tính cũng như trên điện thoại di
động 24/24 giờ, ít lỗi, xử lý nhanh và bảo mật chặt chẽ.
Các yêu cầu này làm đau đầu những chuyên gia phát triển ứng dụng khi phần mềm chủ yếu viết cho
hệ thống này không chạy trên một hệ thống khác bởi nhiều lý do như khác biệt về hệ điều hành, khác
biệt về chuẩn giao tiếp dữ liệu, mạng. Thời gian và chi phí càng trở nên quý báu vì bạn không phải là
người duy nhất biết lập trình. Làm sao sử dụng lại những ứng dụng đã viết để mở rộng thêm nhưng
vẫn tương thích với những kỹ thuật mới?
Sun Microsystems đi đầu trong việc cung cấp giải pháp với Java. Java chạy ổn định trên các hệ điều
hành Unix hay Solaris của Sun từ máy chủ tới các thiết bị cầm tay hay thậm chí trên các hệ điều hành
Windows của Microsoft (một ví dụ rõ ràng đó là hầu hết các điện thoại di động thế hệ mới đều có phần
mềm viết bằng Java). Kiến trúc lập trình dựa trên Java bytecode và thi hành trên máy ảo Java (JVM –
Java Virtual Marchine) cho phép các ứng dụng Java chạy trên bất cứ hệ điều hành nào. Mô hình lập
trình thuần hướng đối tượng của Java giúp các lập trình viên tùy ý sử dụng lại và mở rộng các đối
tượng có sẵn. Các nhà cung cấp công cụ lập trình dựa vào đây đểø gắn vào các môi trường phát triển
ứng dụng bằng Java của mình đủ các thư viện lập trình nhằm hỗ trợ các lập trình viên.
Sức mạnh của Java dường như quá lớn đến nỗi Microsoft từng phải chống trả bằng cách loại bỏ Java
Virtual Marchine khỏi các phiên bản hệ điều hành Windows mới của mình như Windows XP. Tuy nhiên,
Microsoft thừa hiểu rằng dù không cung cấp JVM, Sun cũng có thể tự cung cấp các JVM package cho
những người dùng Windows. Đó là lý do tại sao nhà khổng lồ quyết định bắt tay xây dựng lại từ đầu
một nền tảng phát triển ứng dụng mới: Microsoft.NET Framework.
Vì ra đời khá muộn so với Java, .Net bị coi là khá giống với bậc "tiền bối" của nó. .NET sử dụng kỹ
thuật lập trình thuần hướng đối tượng như Java và cũng thi hành trên một máy ảo là CLR (Common
Language Runtime).
Bộ thư viện của .NET Framework bao gồm hơn 5000 lớp đối tượng đủ sức hỗ trợ hầu hết các yêu cầu
từ phía lập trình viên. Công nghệ mã nguồn mở được đưa vào .NET thay cho COM và DCOM đang được
các lập trình viên của Microsoft sử dụng. Với COM, những thành phần (COMponent) đã được xây dựng
như các lớp thư viện hay các control chỉ có thể sử dụng lại. Bạn không thể mở rộng chúng hay viết lại
cho thích hợp với ứng dụng của mình. Trong .NET, mọi thành phần đều có thể kế thừa và mở rộng,
một kỹ thuật mới được đưa ra thay cho COM là Assembly. Distributed Component hay DCOM là kỹ
thuật dùng để phối hợp các thành phần trên nhiều máy tính giờ đây được thay thế trong .NET bởi
chuẩn công nghệ mới là SOAP và XML Web Service.
Cùng với SOAP (Simple Objects Access Protocol), XML Web Service mở rộng khả năng của DCOM từ
chỗ chỉ phối hợp các máy trong Intranet, nằm sau Firewall ra Internet. Các công ty .com giờ đây mặc
sức xây dựng các phần mềm độc lập của mình những vẫn có thể phối hợp với nhau để đem tới khách
Một điểm nữa không thể bỏ qua khi giới thiệu về .NET Framework, đó là thành phần Common
Language Specification. Vai trò của thành phần này là đảm bảo sự tương tác giữa các đối tượng bất
chấp chúng được xây dựng trong ngôn ngữ nào, miễn là chúng cung cấp được những thành phần
chung của các ngôn ngữ muốn tương tác. Thành phần Common Language Runtime được xây dựng với
mục đích mô tả các yêu cầu cần thiết của một ngôn ngữ để có thể sử dụng trong lập trình và biên dịch
thành mã IL. Một khi đã ở dạng mã IL, ứng dụng đã có thể chạy trên CLR và như thế bạn đã có khả
năng dùng ngôn ngữ lập trình mà mình yêu thích để tận dụng các khả năng mạnh mẽ của .NET.
Trước đây, các lập trình viên đã quen dùng Visual C++ hay Visual Basic 6 hay Visual InterDEV mỗi khi
cần xây dựng một loại ứng dụng khác phải chuyển qua lại giữa các môi trường lập trình khác nhau của
Visual Studio 98 và chợt nhận ra rằng VB 6 không có điểm mạnh này của C++ hoặc C++ không làm
nhanh được chức năng kia của VB 6,… sẽ cảm thấy nhẹ nhõm vì với .NET giờ đây, mọi sức mạnh của
các ngôn ngữ lập trình đều như nhau. .NET Framework hỗ trợ một bộ thư viện lập trình đồ sộ hơn
5000 lớp đối tượng để bạn đủ khả năng xây dựng các loại ứng dụng từ kiểu console (ứng dụng dòng
lệnh), ứng dụng trên Windows cho tới các ứng dụng Web, các service của hệ điều hành và các Web
service trên Internet.
Trước khi chấm dứt phần giới giới thiệu, cũng cần phải đề cập đến bộ control đồ sộ và mới mẻ của
.NET. Rất nhiều điều khiển mới được thêm vào .NET Framework để hỗ trợ cho các ứng dụng có giao
diện đồ họa trên Windows và trên Web một "vẻ mặt" mới. Những công cụ này không chỉ hỗ trợ chuẩn
font chữ Unicode nhưng còn kết hợp với khả năng xây dựng ứng dụng mang tính "quốc tế" khi người
lập trình phải đáp ứng nhiều ngôn ngữ, nhiều định dạng ngày giờ hay tiền tệ khác nhau.
Microsoft không quên đem lại một môi trường phát triển ứng dụng sử dụng giao diện đồ hoạ, tích hợp
nhiều chức năng, tiện ích khác nhau để hỗ trợ tối đa cho các lập trình viên, đó chính là Visual
Studio.NET.
.NET Framework là thành phần quan trọng nhất trong kỹ thuật phát triển ứng dụng dựa trên .NET.
Visual Studio sẽ giúp người lập trình nắm bắt và tận dụng tốt hơn những chức năng của .NET
Framework. Phần dưới đây giới thiệu những kiến thức cơ bản nhất về .NET Framework trước khi chúng
ta thực sự bắt tay vào làm việc với Visual Studio.NET và VB.NET.
VB C ++ C# J# …
B a s e C la s s L ib ra ry
Operating System
II.2. Cung cấp các chức năng xây dựng ứng dụng
Với vai trò quản lý việc xây dựng và thi hành ứng dụng, .NET Framework cung cấp các lớp đối tượng
(Class) để bạn có thể gọi thi hành các chức năng mà đối tượng đó cung cấp. Tuy nhiên, lời kêu gọi của
bạn có được "hưởng ứng" hay không còn tùy thuộc vào khả năng của hệ điều hành đang chạy ứng
dụng của bạn.
Các chức năng đơn giản như hiển thị một hộp thông báo (Messagebox) sẽ được .NET Framework sử
dụng các hàm API của Windows. Chức năng phức tạp hơn như sử dụng các COMponent sẽ yêu cầu
Windows phải cài đặt Microsoft Transaction Server (MTS) hay các chức năng trên Web cần Windows
phải cài đặt Internet Information Server (IIS).
Như vậy, bạn cần biết rằng lựa chọn một hệ điều hành để cài đặt và sử dụng .NET Framework cũng
không kém phần quan trọng. Cài đặt .NET Framework trên các hệ điều hành Windows 2000, 2000
Server, XP, XP.NET, 2003 Server sẽ đơn giản và tiện dụng hơn trong khi lập trình.
Với hơn 5000 lớp đối tượng để gọi thực hiện đủ các loại dịch vụ từ hệ điều hành, chúng ta có thể bắt
đầu xây dựng ứng dụng bằng Notepad.exe!!!… Nhiều người lầm tưởng rằng các môi trường phát triển
phần mềm như Visual Studio 98 hay Visual Studio.NET là tất cả những gì cần để viết chương trình.
Thực ra, chúng là những phần mềm dùng làm "vỏ bọc" bên ngoài. Với chúng, chúng ta sẽ viết được
các đoạn lệnh đủ các màu xanh, đỏ; lỗi cú pháp báo ngay khi đang gõ lệnh; thuộc tính của các đối
tượng được đặt ngay trên cửa sổ properties, giao diện được thiết kế theo phong cách trực quan… Như
vậy, chúng ta có thể hình dung được tầm quan trọng của .NET Framework. Nếu không có cái cốt lõi
.NET Framework, Visual Studio.NET cũng chỉ là cái vỏ bọc! Nhưng nếu không có Visual Studio.NET,
công việc của lập trình viên .NET cũng lắm bước gian nan!
II.4.3. ASP.NET
Bộ thư viện các lớp đối tượng dùng trong việc xây dựng các ứng dụng Web. ASP.NET không phải là
phiên bản mới của ASP 3.0. Ứng dụng web xây dựng bằng ASP.NET tận dụng được toàn bộ khả năng
của .NET Framework. Bên cạnh đó là một "phong cách" lập trình mới mà Microsoft đặt cho nó một tên
gọi rất kêu : code behind. Đây là cách mà lập trình viên xây dựng các ứng dụng Windows based
thường sử dụng – giao diện và lệnh được tách riêng. Tuy nhiên, nếu bạn đã từng quen với việc lập
trình ứng dụng web, đây đúng là một sự "đổi đời" vì bạn đã được giải phóng khỏi mớ lệnh HTML lộn
xộn tới hoa cả mắt.
Sự xuất hiện của ASP.NET làm cân xứng giữa quá trình xây dựng ứng dụng trên Windows và Web.
ASP.NET cung cấp một bộ các Server Control để lập trình viên bắt sự kiện và xử lý dữ liệu của ứng
dụng như đang làm việc với ứng dụng Windows. Nó cũng cho phép chúng ta chuyển một ứng dụng
trước đây viết chỉ để chạy trên Windows thành một ứng dụng Web khá dễ dàng. Ví dụ cho các lớp
trong thư viện này là WebControl, HTMLControl, …
Ví dụ, công ty du lịch của bạn đang sử dụng một hệ thống phần mềm để ghi nhận thông tin về khách
du lịch đăng ký đi các tour. Để thực hiện việc đặt phòng khách sạn tại địa điểm du lịch, công ty cần
biết thông tin về phòng trống tại các khách sạn. Khách sạn có thể cung cấp một Web service để cho
biết thông tin về các phòng trống tại một thời điểm. Dựa vào đó, phần mềm của bạn sẽ biết rằng liệu
có đủ chỗ để đặt phòng cho khách du lịch không? Nếu đủ, phần mềm lại có thể dùng một Web service
khác cung cấp chức năng đặt phòng để thuê khách sạn. Điểm lợi của Web service ở đây là bạn không
cần một người làm việc liên lạc với khách sạn để hỏi thông tin phòng, sau đó, với đủ các thông tin về
nhiều loại phòng người đó sẽ xác định loại phòng nào cần đặt, số lượng đặt bao nhiêu, đủ hay không
đủ rồi lại liên lạc lại với khách sạn để đặt phòng. Đừng quên là khách sạn lúc này cũng cần có người để
làm việc với nhân viên của bạn và chưa chắc họ có thể liên lạc thành công.
Web service được cung cấp dựa vào ASP.NET và sự hỗ trợ từ phía hệ điều hành của Internet
Information Server.
5000 tên có sẵn, việc đặt trùng tên lớp của mình với một lớp đối tượng đã có là điều khó tránh khỏi.
Namespace cho phép việc này xảy ra bằng cách sử dụng một tên đầy đủ để nói đến một lớp đối tượng.
Ví dụ, nếu muốn dùng lớp WebControls, chúng ta có thể dùng tên tắt của nó là WebControls hay tên
đầy đủ là System.Web.UI.WebControls.
System.Web System.Windows.Forms
Services UI Design
Description HtmlControls
Discovery WebControls
Protocols System.Drawing
Caching Security Drawing2D Printing
Configuration SessionState Imaging Text
System.Data System.Xml
OleDb SqlClient XSLT Serialization
Common SQLTypes XPath
System
Collections IO Security Runtime
Configuration Net ServiceProces InteropServices
Diagnostics Reflection Text Remoting
Đặc điểm của bộ thư viện các đối tượng .NET Framework là sự trải rộng để hỗ trợ tất cả các ngôn ngữ
lập trình .NET như chúng ta thấy ở hình vẽ trên. Điều này sẽ giúp những người mới bắt đầu ít bận tâm
hơn trong việc lựa chọn ngôn ngữ lập trình cho mình vì tất cả các ngôn ngữ đều mạnh ngang nhau.
Cũng bằng cách sử dụng các lớp đối tượng để xây dựng ứng dụng, .NET Framework buộc người lập
trình phải sử dụng kỹ thuật lập trình hướng đối tượng (sẽ được nói tới trong các chương sau).
Màn hình khởi đầu của VS.NET 2003 với Tab My Profile hiện hành
Solution Explorer quản lý một hay nhiều project được nhóm với nhau để tạo thành một solution (giải
pháp hay một hệ thống ứng dụng hoàn chỉnh). Nếu chuyển qua tab Class (Clas…), cửa sổ này liệt kê
các lớp đối tượng trong ứng dụng đang làm việc. Tab Content (Cont…) sẽ hiện thị mục lục của phần
giúp đỡ của VS.NET.
Dynamic help là cửa sổ giúp đỡ thông minh mới có trong VS.NET. Trong khi lập trình, chúng ta chỉ cần
đưa chuột tới một từ khoá như Class, For,… Dynamic help sẽ tự động tìm ra những mục giúp đỡ liên
quan đế từ khoá đó. Nếu chúng ta đang mở một project, phần cửa sổ dành cho Dynamic help còn
dùng để hiển thị cửa số Property giống như của VB 6.
Toolbox liệt kê các control dành cho việc thiết kế giao diện. Một tiện lợi của VS.NET cho các màn hình
độ phân giải thấp là chúng ta có thể thu gọn các cửa sổ kiểu như Solution Explorer và Dynamic help
thành tab nằm dọc theo màn hình như cửa sổ Toolbox chúng ta thấy trong hình. Nếu có nhiều tab,
biểu tượng của tab đó sẽ được hiển thị. Trong hình vẽ một tab khác có tên là Server Explorer được
hiển thị với biểu tượng 2 chiếc máy tính phía trên tab Toolbox.
định. Ví dụ, loại template Windows Application sẽ được VS.NET tạo sẵn một form và phát sinh lệnh cần
thiết để chúng ta có thể chạy ứng dụng ngay sau khi vừa tạo mới!
Hãy bắt đầu bằng ứng dụng phổ biến nhất : Windows Application.
Đặt lại tên cho project trong phần Name là “Hello” và định lại đường dẫn cho thư mục lưu trữ ứng
dụng trong phần Location (tuỳ ý và nếu cần thiết). Cuối cùng, nhấn OK để VS.NET phát sinh project
mới
Trong ứng dụng này, chúng ta sẽ thực hiện các chức năng sau:
Thiết kế giao diện để làm quen với control mới và thuộc tính mới của các control
Thiết kế hệ thống thực đơn (menu)
Tìm hiểu cấu trúc của một ứng dụng Windows Application về mặt mã lệnh
Viết lệnh và làm quen với giao diện mới của cửa sổ code editor
Biên dịch, chạy thử ứng dụng
Tìm hiểu danh sách các file của project
Trước hết, nhấn đúp trên form để xem cửa sổ code editor với các đoạn lệnh của form Form1.
Inherits System.Windows.Forms.Form
Inherits có nghĩa là "kế thừa". Trong lập trình HĐT, điều này có nghĩa là Class được khai báo có đặc
điểm giống hoàn toàn với class mà nó thừa kế. Ở đây, class mà Form1 thừa kế là
System.Windows.Forms.Form. Như vậy, Form1 sẽ có đặc điểm chung giống với bất kỳ form nào trong
các ứng dụng Windows: Một vùng hình chữ nhật, có thanh tiêu đề, các hộp Maximize, Minimize, X; có
thể thay đổi kích thước,…
Tạm bỏ qua phần Windows Form designer generated code để xem phần thủ tục Form1_Load:
Như đã từng quen với VB 6, chúng ta biết rằng đây chính là thủ tục bẫy sự kiện Load của form xảy ra
khi chương trình vừa được thi hành. Hãy chú ý đoạn Handles MyBase.Load ở cuối phần khai báo. Với
mỗi thủ tục xử lý sự kiện, giờ đây, VB.NET dùng từ khoá Handles để mô tả sự kiện sẽ xử lý. Viết đoạn
lệnh sau đây để hiển thị một hộp thông báo trong thủ tục Form1_Load:
MsgBox("Form load!!!")
Nhấn F5 để chạy thử chương trình, một hộp thông báo hiển thị câu "Form load!!!" trước khi form được
hiện ra. Bây giờ, chúng ta hãy bỏ phần Handles MyBase.Load và chạy lại : hộp thông báo không còn
hiện ra được nữa – nghĩa là không có dòng lệnh nào cho xử lý sự kiện Load của form.
Chúng ta sẽ đi vào xem xét chi tiết đoạn lệnh được phát sinh trên đây để hiểu rõ thêm một vài điểm
trong lập trình hướng đối tượng.
Trong lập trình HĐT, mỗi một đối tượng (object) đều phải có một lớp đối tượng (class) định nghĩa nó.
Lớp đối tượng chỉ là một khái niệm chẳng hạn như Máy tính, còn đối tượng là một cái máy tính cụ thể
chúng ta đang dùng. Một lớp được định nghĩa trong VB.NET bằng từ khoá Class như trong chương
trình, chúng ta có một lớp là Form1. Từ đây, chúng ta dùng từ class thay cho cụm từ "lớp đối tượng"
để ngắn gọn hơn.
Một class cần định nghĩa cách đối tượng của nó được tạo ra và huỷ đi. Điều này giống như việc Toyota
tạo ra một model xe hơi mới có tên là VIOS sẽ định nghĩa quy trình sản xuất ra một chiếc VIOS cụ thể
như thế nào. Thủ tục mô tả cách tạo ra một đối tượng của class phải đặt tên là New. Trong đoạn lệnh,
bạn thấy class Form1 cũng có một thủ tục New. Thủ tục định nghĩa cách huỷ đi một đối tượng gọi là
Dispose.
Sau khi các chiếc xe VIOS được đưa vào sử dụng, Toyota nhận được phản hồi từ khách hàng và quyết
định đưa ra một phiên bản VIOS mới hơn là VIOS Pro. VIOS Pro chính là một model mới dựa trên
model VIOS trước đó với một số chức năng cải tiến và vài thiết bị gắn thêm. Trong lập trình HĐT, ta
gọi đây là sự kế thừa. Trở lại phần khai báo Class Form1, bạn sẽ thấy phần Inherits
System.Windows.Forms.Form. Điều này có nghĩa là class Form1 kế thừa đặc điểm của class Form. Dĩ
nhiên các kỹ sư của Toyota sẽ không bỏ thời gian định nghĩa lại cách tạo ra một chiếc VIOS Pro, thay
vào đó họ sẽ mô tả rằng "một chiếc VIOS Pro được tạo ra giống như một chiếc VIOS cộng thêm một số
thay đổi …" Lập trình HĐT cũng dùng cách này, chúng ta thấy trong Sub New() có đoạn lệnh
MyBase.New(). Từ khoá MyBase dùng để nói đến lớp cha của Form1 tức Form. Như thế, Form1 sẽ
được tạo ra giống như một Form bình thường cộng với một vài thay đổi. Những thay đổi này được liệt
kê trong phần InitializeComponent().
Form1 là một Form bình thường mà chúng ta đã gắn thêm một label và một textbox. Thủ tục
InitializeComponent() mô tả cách chúng ta gắn thêm label và textbox đó.
'Label1
Me.Label1.AutoSize = True
Me.Label1.Location = New System.Drawing.Point(16, 32)
Me.Label1.Name = "Label1"
Me.Label1.Size = New System.Drawing.Size(67,16)
Me.Label1.TabIndex = 0
Me.Label1.Text = "Tên của bạn"
'txtTen
Me.txtTen.Location = New System.Drawing.Point(88,24)
Me.txtTen.Name = "txtTen"
Me.txtTen.TabIndex = 1
Me.txtTen.Text = ""
'Form1
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(296,69)
Me.Controls.Add(Me.txtTen)
Me.Controls.Add(Me.Label1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
Windows Form Designer khai báo hai biến Label1 và txtTen bằng từ khoá Friend (Các từ khoá Public,
Private, Friend,… sẽ được chúng tôi trình bày trong chương 3.) Biến Label1 được khai báo là một đối
tượng của class Label trong khi txtTen là đối tượng của class TextBox. Khai báo một đối tượng không
có nghĩa là chúng ta đã có thể sử dụng đối tượng. Điều này giống như việc đặt hãng Toyota một chiếc
VIOS và phải đợi họ giao hàng trước khi sử dụng. Trong lập trình HĐT, biến kiểu đối tượng sau khi khai
báo cần được "tạo mới". Đây là lý do có hai dòng lệnh:
Từ khoá Me cũng như các đoạn lệnh còn lại không xa lạ với chúng ta. Ở đây, Designer đang khởi gán
các thuộc tính cho Label1 và txtTen. Một chú ý nhỏ là để đặt vị trí của Label hay TextBox trên Form1,
designer sử dụng một điểm để canh góc trên bên trái. Điểm cũng là một đối tượng của class Point và
được tạo ra bằng lệnh New System.Drawing.Point(x,y).
Hai dòng lệnh Controls.Add(…) làm công việc "bắt vít" hai điều khiển của chúng ta vào Form1.
Và tạo mới:
Trước mục ghi chú ‘Form1, thêm đoạn lệnh để đặt thuộc tính cho LinkLabel:
'LinkLbl
Me.LinkLbl.Location = New System.Drawing.Point(112, 48)
Me.LinkLbl.Name = "LinkLbl"
Me.LinkLbl.Size = New System.Drawing.Size(64, 16)
Me.LinkLbl.TabIndex = 2
Me.LinkLbl.TabStop = True
Me.LinkLbl.Text = "Giúp đỡ"
Me.LinkLbl.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
Cuối cùng, chúng ta cũng "bắt vít" LinkLabel vừa tạo vào Form1 bằng lệnh:
Me.Controls.Add(Me.LinkLbl)
Bây giờ, chúng ta có thể biên dịch và chạy thử chương trình bằng cách nhấn phím F5. Các chức năng
khá đơn giản, ngoài việc chúng ta đã dùng một điều khiển LinkLabel mới có trong .NET để mở website
http://ncmlt.hcmuns.edu.vn trong Internet Explorer. Trong đoạn lệnh dành cho chức năng này, chúng
ta dùng một đối tượng P của class Process. Đây là một đối tượng "hệ thống" chưa từng có trong VB 6.
Đối tượng này có thể khởi động hay tắt các ứng dụng có trên máy một cách đơn giản như chúng ta
được thấy.
Reference là một mục liệt kê tất cả các lớp thư viện mà chương trình của chúng ta đang "tham khảo".
Mỗi mục trong Reference là một namespace hay một thư viện nhiều class. Trong chương trình, chúng
ta chỉ có quyền khai báo biến đối tượng là một đối tượng của các class có trong namespace đã liệt kê
trong phần References.
Kỹ thuật lập trình HĐT bao gồm hai điểm quan trọng: Xây dựng các lớp đối tượng (Component) và sử
dụng lại những đối tượng có sẵn. Một ứng dụng đơn giản có thể chỉ cần ghép nối những đối tượng có
sẵn mà thành như trong ứng dụng Hello. Reference chính là nơi khai báo những thành phần cần thiết
để ghép nối thành một ứng dụng và chúng ta không cần phải khai báo những thành phần thừa như
System.XML.
Với những ứng dụng phức tạp hơn, chúng ta sẽ cần tự mình tạo ra những đối tượng mới. Trong ví dụ
này, chúng ta sẽ tạo ra lớp đối tượng có tên là SayHi để nói lời chào tuỳ theo buổi sáng, trưa hay tối.
Trước hết, hãy chuyển qua tab Class trên cửa sổ Solution Explorer để xem cấu trúc của class Form1
(hình trên)
Ví dụ:
Public Class SayHi
Dim mTen As String
Tạm thời không cần quan tâm nhiều đến cú pháp vì chúng ta sẽ tìm hiểu trong phần lập trình hướng
đối tượng. Sau khi đã viết đoạn lệnh, xem trong cửa sổ Class viewer bạn sẽ thấy các thành phần của
class SayHi được liệt kê bao gồm một thuộc tính có tên là Ten, hai phương thức là New và Say cùng với
một biến cục bộ là mTen. Thuộc tính của một class cho biết đặc điểm mà một đối tượng của nó sẽ có.
Phương thức của một class cho biết khả năng mà đối tượng của nó có thể thực hiện.
Cửa sổ Class viewer có thêm class SayHi và các thành phần của nó
Chúng ta sẽ sửa lại đoạn lệnh trong nút cmdHello để xem cách dùng một đối tượng:
Ví dụ:
Private Sub cmdHello_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles cmdHello.Click
Dim sh As SayHi, LoiChao As String
sh = New SayHi(txtTen.Text)
LoiChao = sh.Say
MsgBox(LoiChao)
End Sub
Chúng ta thấy, sử dụng class SayHi cũng giống như sử dụng class TextBox hay Label trong phần
InitializeComponent.
cách nhắp chuột phải và chọn mục Delete. Sau đó, đưa SayHi.vb vào project bằng cách nhắp chuột
phải trên project SayHi và chọn mục Add | Add existing item… Tìm SayHi.vb trong thư mục Hello của
project Hello và chọn Open.
Lúc này, chúng ta đã có file SayHi.dll và sẵn sàng sử dụng nó trong các ứng dụng khác. Hình dưới hiển
thị một phần cửa sổ Windows Explorer để xác định vị trí của file SayHi.dll
Kết quả biên dịch được lưu giữ trong thư mục Bin của ứng dụng
Tiếp theo đây, chúng ta sẽ xây dựng một ứng dụng console (giao diện dòng lệnh như của DOS) để sử
dụng class SayHi đã tạo ra. Chọn mục File | Close Solution để đóng solution hiện có.
Nếu lúc này chạy thử chương trình, một cửa sổ DOS sẽ nháy lên rồi biến mất. Ứng dụng chỉ chạy trong
"nháy mắt"! Chúng ta hãy thêm dòng lệnh sau trước khi nhấn lại phím F5
System.Console.ReadLine()
Khi chương trình chạy, chúng ta thấy một cửa sổ "đen ngòm" của DOS hiện ra với cursor nhấp nháy tại
góc trên bên trái. Dấu nhắc này có nghĩa ứng dụng đang chờ chúng ta nhấn phím Enter để kết thúc.
Bây giờ, hãy thực hiện bước "ghép nối" các thành phần có sẵn trong đó, thành phần ghép nối chính là
SayHi. Trong cửa sổ Solution Explorer, nhắp chuột phải trên mục Reference và chọn mục Add
reference. Chọn nút Browse và tìm file SayHi.dll. Sau khi chọn Open, chúng ta sẽ thấy mục Selected
Components liệt kê file SayHi.dll. Chọn nút OK để tham chiếu.
Khi chạy chương trình, bạn sẽ thấy cửa sổ hiện ra như bên dưới:
Vì mỗi ứng dụng nằm riêng một chỗ, tự quản lý các assembly của mình nên DLL hell khó lòng xảy ra
được nữa.
Assembly được chia làm hai loại:
Private assembly là những assembly như mô tả ở trên nghĩa là của ứng dụng nào thì chỉ ứng dụng
đó dùng được.
Public assembly là những assembly đem dùng chung cho nhiều ứng dụng.
Hãy xét tới trường hợp một công ty phần mềm không phải chỉ có một ứng dụng nhưng một họ các ứng
dụng cung cấp cho người dùng. Nhiều ứng dụng trong đó đều sử dụng chung một assembly. Công ty
có thể chọn hai giải pháp: dùng private assembly để mỗi ứng dụng quản lý assembly của riêng mình
hoặc, dùng public assembly để nhiều ứng dụng chỉ dùng chung một assembly mà thôi. Cách thứ hai sẽ
tiện lợi hơn cho người dùng mỗi khi họ muốn nâng cấp lên phiên bản mới của công ty.
Các assembly dùng chung được quản lý bởi Global Assembly Cache (GAC). Đây là thư mục nằm trong
thư mục Windows\Assembly\GAC. GAC quản lý các assembly này thông qua tên gọi riêng là Strong
name. Strong name được phát sinh thông qua công cụ sn.exe của .NET Framework.
Bài 2
NGÔN NGỮ VISUAL BASIC .NET
Tóm tắt
Lý thuyết 3 tiết - Thực hành 5 tiết
Đưa ra những điểm mới và những 1. Các kiểu dữ liệu và đặc điểm 1.1, 1.2, 1.3
điểm thay đổi (so với VB) trong Visual 2. Biến – Tính chất, khai báo và khởi
Basic .Net tạo
3. Mảng, Structure
4. Các toán tử
5. Cấu trúc điều khiển
6. Xử lý lỗi
7. Những thay đổi trong VB.NET
Khi khai báo một kiểu dữ liệu cơ bản, không hẳn biến sẽ sử dụng vùng nhớ như yêu cầu lưu trữ. Ví
dụ, mảng cần thêm vùng nhớ cho chính bản thân mảng cũng như cho mỗi chiều (dimension). Mỗi biến
Object tham chiếu đến một thành phần hoặc một kiểu hỗn hợp sử dụng 4 byte vùng nhớ ngoài số vùng
nhớ cần dùng cho kiểu dữ liệu chứa trong nó.
Phương thức
Tên Mô tả
Clone Trả về một tham chiếu của biến.
Compare Phương thức so sánh hai tham số kiểu String dựa vào thứ tự các ký tự theo ngôn
ngữ qui định trong Regional Settings của từng ký tự và trả về:
-1 khi chuỗi thứ 1 nhỏ hơn chuỗi thứ 2
0 khi chuỗi thứ 1 bằng chuỗi thứ 1
1 khi chuỗi thứ 1 lớn hơn chuỗi thứ 2
Ngoài ra có thể có tham số qui định có phân biệt chữ Hoa chữ thường, v.v…
CompareOrdinal So sánh hai tham số kiểu String dựa theo bảng mã các ký tự của các tham số.
Hàm trả về hiệu của mã tham số thứ nhất và mã tham số thứ hai.
Concat Nối các tham số lại với nhau và trả về chuỗi nối.
Copy Tạo một thể hiện mới kiểu String có giá trị như tham số chuỗi truyền vào.
CopyTo Sao chép một số ký tự chỉ ra từ một vị trí trên biến vào một vị trí chỉ ra trên mảng
ký tự với số lượng ký tự truyền vào.
EndsWith Trả về True/False cho biết các ký tự cuối của biến có khớp với chuỗi chỉ ra không.
Format Thay thế phần biểu thức định dạng trong chuỗi bằng các các giá trị tương ứng đã
được định dạng theo biểu thức.
IndexOf Trả về vị trí đầu tiên tìm thấy chuỗi hoặc ký tự truyền vào trên biến, ; có thể sử
dụng thêm vị trí bắt đầu tìm, trả về vị trí lần tìm thấy thứ mấy.
IndexOfAny Trả về vị trí tìm thấy đầu tiên trên biến bất kỳ ký tự nào trong mảng ký tự truyền
vào; có thể sử dụng thêm vị trí bắt đầu tìm, trả về vị trí lần tìm thấy thứ mấy.
Insert Chèn vào một giá trị String truyền vào tại vị trí chỉ định trên biến.
Join Nối các phần tử của mảng String truyền vào thành một chuỗi duy nhất với dấu nối
là chuỗi dấu ngăn cách chỉ ra (separator)
LastIndexOf Trả về vị trí tìm thấy cuối cùng trên biến, chuỗi hoặc ký tự truyền vào; có thể sử
dụng thêm vị trí bắt đầu tìm, trả về vị trí lần tìm thấy thứ mấy.
LastIndexOfAny Trả về vị trí tìm thấy cuối cùng trên biến bất kỳ ký tự nào trong mảng ký tự truyền
vào; có thể sử dụng thêm vị trí bắt đầu tìm, trả về vị trí lần tìm thấy thứ mấy.
PadLeft Nối thêm bên trái ký tự truyền vào với số lần sao cho độ dài tổng cộng bằng độ
dài chỉ ra. Nếu độ dài tổng cộng chỉ ra nhỏ hơn độ dài của biến, không ký tự nào
được thêm vào.
PadRight Nối thêm bên phải ký tự truyền vào với số lần sao cho độ dài tổng cộng bằng độ
dài chỉ ra. Nếu độ dài tổng cộng chỉ ra nhỏ hơn độ dài của biến, không ký tự nào
được thêm vào.
Remove Xóa bỏ một số ký tự chỉ ra khỏi biến từ vị trí truyền vào.
Replace Thay thế tất cả ký tự hay chuỗi tìm thấy trên biến bằng ký tự hay chuỗi truyền
vào.
Split Trả về một mảng String với các phần tử chứa các chuỗi con được ngắt ra từ biến
tùy theo ký tự ngăn cách truyền vào.
StartsWith Cho biết trị bắt đầu của biến có khớp với chuỗi truyền vào.
Substring Trả về một chuỗi con từ biến.
ToLower Trả về bản sao của biến với các ký tự in thường.
ToUpper Trả về bản sao của biến với các ký tự in HOA.
Trim Trả về biến đã loại bỏ tất cả các ký tự từ đầu đến cuối của biến khớp với mảng ký
tự truyền vào.
TrimEnd Trả về biến đã loại bỏ tất cả các ký tự từ vị trí cuối của biến khớp với mảng ký tự
truyền vào.
TrimStart Trả về biến đã loại bỏ tất cả các ký tự từ vị trí đầu của biến khớp với mảng ký tự
truyền vào.
Thuộc tính
Tên Mô tả
Date Trả về giá trị ngày tháng năm của biến.
Day Trả về giá trị ngày trong tháng của biến.
DayOfWeek Trả về giá trị ngày trong tuần của biến, với ngày đầu tiên là Chủ nhật có giá trị là
0.
DayOfYear Trả về giá trị ngày trong năm của biến.
Hour Trả về giá trị giờ của biến.
Millisecond Trả về giá trị phần ngàn giây của biến.
Minute Trả về giá trị phút của biến.
Month Trả về tháng của biến.
Now Trả về giá trị ngày giờ hiện hành của hệ thống.
Second Trả về giá trị giây của biến.
TimeOfDay Trả về giá trị giờ phút giây của biến.
Today Trả về ngày hiện hành.
Year Trả về năm của biến.
Phương thức
Tên Mô tả
AddDays Thêm số ngày truyền vào cho giá trị của biến.
AddHours Thêm số giờ truyền vào cho giá trị của biến.
AddMilliseconds Thêm số phần ngàn giây truyền vào cho giá trị của biến.
AddMinutes Thêm số phút truyền vào cho giá trị của biến.
AddMonths Thêm số tháng truyền vào cho giá trị của biến.
AddSeconds Thêm số giây truyền vào cho giá trị của biến.
AddYears Thêm số năm truyền vào cho giá trị của biến.
Compare So sánh hai biến ngày giờ và cho biết biến nào lớn hơn.
CompareTo So sánh biến với một tham số Object.
DaysInMonth Cho biết số ngày trong tháng theo tham số tháng, năm truyền vào.
IsLeapYear Cho biết giá trị năm truyền vào (dạng yyyy) có phải là năm nhuận hay không.
Subtract Trừ một giá trị thời gian khỏi biến.
ToLongDateString Chuyển giá trị biến ra định dạng Long Date.
ToLongTimeString Chuyển giá trị biến ra định dạng Long Time.
ToShortDateString Chuyển giá trị biến ra định dạng Short Date.
ToShortTimeString Chuyển giá trị biến ra định dạng Short Time.
ToString Trả về chuỗi trị của biến theo định dạng truyền vào
Field
Tên Mô tả
MaxValue Hiển thị giá trị lớn nhất của kiểu (chỉ đọc).
MinValue Hiển thị giá trị nhỏ nhất của kiểu (chỉ đọc).
Ngoại trừ kiểu String, các kiểu khác khi muốn chuyển sang kiểu chuỗi đều có thể dùng phương thức
ToString (kế thừa từ lớp Object) để chuyển đổi và định dạng cùng lúc.
Cú pháp sử dụng:
ToString()
ToString(<biểu thức định dạng>)
g, G Định dạng tổng quát 12345.67 ToString(“G”) hiển thị 12345.67 tùy theo gía trị
có thể hiện thị dưới dạng E hoặc F
n, N Định dạng số 12345.67 ToString(“N”) hiển thị 12,345.67
p, P Định dạng phần trăm 0.45 ToString(“P”) hiển thị 45 %
x, X Định dạng Thập lục phân 250 ToString(“X”) hiển thị FA
Ngoài ra chúng ta cũng có thể sử dụng các ký tự sau đây để lập biểu thức định dạng
If x <> 0 then
Dim a as Integer
a = 1/x
End If
MsgBox CStr(a))
Đoạn lệnh trên sẽ gây lỗi tại dòng MsgBox CStr(a)) vì biến a chỉ có phạm vi sử dụng trong khối
lệnh If … End If
Khi biến được khai báo trong một thủ tục nhưng không trong một khối lệnh, biến sẽ có phạm vi
sử dụng trong toàn thủ tục. Đây là trường hợp đặc biệt của phạm vi khối lệnh với khối lệnh là
toàn bộ thủ tục.
Biến có phạm vi khối lệnh và phạm vi thủ tục là biến cục bộ.
Phạm vi module và phạm vi project
Có những khác biệt trong phạm vi sử dụng đối với các biến khai báo chung trong Module chuẩn
(Standard module) và Lớp (Class module). Trước tiên, chúng ta cần lưu ý rằng bản thân Module
chuẩn được khai báo với một trong ba từ khóa sau: Public, Friend và Private (mặc định)
Tùy theo từ khóa mà phạm vi sử dụng của các thành phần trong module bị giới hạn. Ví dụ một
biến Public khai báo trong một module Friend sẽ có phạm vi sử dụng Friend
+ Truy xuất Private
Nếu biến được khai báo trên phần Declaration của module với từ khóa Private sẽ chỉ có
phạm vi sử dụng trong module.
Dim x as Integer
Để nhấn mạnh vai trò của hàm tạo (constructor), chúng ta có thể viết:
Khi khai báo nhiều biến trên cùng dòng và không chỉ ra kiểu của biến, biến sẽ lấy kiểu dữ liệu của biến
khai báo dữ liệu tường minh tiếp sau đó
Trong cách này, phải khai báo tường minh kiểu dữ liệu cho từng biến.
Với các biến kiểu đối tượng, cách khai báo cũng như thế
Lệnh trên chưa tạo ra biến đối tượng và sau dòng lệnh, objA vẫn là Nothing
Những cách sau đây sẽ khai báo và tạo biến đối tượng:
Hoặc
Hoặc
nhưng sẽ gán cho biến bốn byte chứa địa chỉ của đối tượng. Tóm lại, biến kiểu trị chứa giá trị của biến
còn biến kiểu tham chiếu chỉ đến nơi chứa giá trị.
Sự khác biệt này dẫn đến nhiều hệ quả mà phép gán là một. Để minh họa chúng ta xem Class sau với
một thuộc tính:
Ví dụ:
Structure ConNguoi
Public tuoi as Short
End Structure
Khi được gán cho nhau, hai biến tham chiếu Ng1, Ng2 cùng chứa địa chỉ trỏ đến một đối tượng. Vì vậy
thay đối giá trị của thuộc tính tuoi trên biến này, thay đổi cũng phản ánh trên biến kia.
Ngược lại, khi được gán cho nhau, biến tham trị sẽ tạo nên một vùng nhớ chứa trị mới, hai biến trị
CNg1, CNg2 cùng chứa trị như nhau nhưng trên hai vùng nhớ khác nhau. Do đó, giá trị của thuộc tính
tuoi của hai biến được chứa trên hai vùng nhớ và độc lập nhau.
Chú ý: Kiểu String cũng là kiểu tham chiếu nhưng có một số đặc tính của kiểu trị.
Chúng ta xét đoạn lệnh sau:
Chúng ta nghĩ rằng ch1 chứa "Chuỗi 2", nhưng ch1 lại chứa "Chuỗi 1". Lý do như sau: khi biến kiểu
String đã được tạo ra, giá trị của chúng không thể sửa đổi. Sửa đổi trị của biến String là tạo ra một thể
hiện mới chứa nội dung sửa đổi. Do vậy:
Khi gán ch2 = ch1, ch2 trỏ đến cùng một chuỗi như ch1
Nhưng khi gán ch2 = "Chuỗi 2" do không thể thay đổi giá trị nên ch2 trỏ đến một thể hiện mới
khác với ch1
Bảng sau đây cho biết kiểu dữ liệu thuộc kiểu trị hay kiểu tham chiếu:
Phân loại
Value Type Reference Type
Cú pháp:
Ví dụ:
Khi không chỉ ra trị hằng, VB.NET sẽ gán trị cho thành phần đầu tiên là 0 và tăng dần cho các thành
phần kế tiếp:
Ví dụ:
Nếu chỉ gán trị hằng cho thành phần đầu tiên, các thành phần kế tiếp sẽ nhận giá trị tăng dần:
Sau khi khai báo kiểu Enum, chúng ta có thể khai báo biến kiểu Enum cũng như sử dụng các thành
phần của kiểu này thay cho các trị hằng.
Dim a As DoTuoi
a =
Hoặc
Dim a as Integer()
Khai báo có khởi tạo kích thước nhưng không khởi tạo giá trị ban đầu:
Khai báo có khởi tạo kích thước và khởi tạo giá trị ban đầu:
Hoặc
Hoặc
Chú ý: Khi dấu { } rỗng, các phần tử có giá trị khởi tạo là giá trị mặc định của kiểu dữ liệu.
Mảng có kiểu tham chiếu nên khi gán hai biến mảng cho nhau, biến được gán sẽ là một tham chiếu
đến mảng bên phải toán tử =, khác với trong VB6, là tạo ra một mảng mới có số phần tử mang trị
giống nhau.
Mảng thuộc lớp System.Array nên có các thuộc tính và phương thức của lớp này. Sau đây là một số
thuộc tính và phương thức đáng chú ý:
Thuộc tính
Tên Mô tả
Length Số phần tử của mảng
Rank Số chiều của mảng
Phương thức
Tên Mô tả
BinarySearch Tìm kiếm trên mảng một chiều đã được sắp xếp giá trị truyền vào, sử dụng
thuật giải tìm kiếm nhị phân.
Clear Gán các phần tử trong dãy chỉ ra bằng giá trị mặc định của kiểu dữ liệu các phần
tử
Clone Trả về bản sao cạn (shallow copy) của mảng. Bản sao này chỉ sao chép kiểu trị
và kiểu tham chiếu nhưng không sao chép các đối tượng được tham chiếu đến.
Copy Sao chép một phần của mảng vào mảng khác và thực hiện chuyển đổi kiểu nếu
cần.
CopyTo Sao chép toàn bộ các phần tử của mảng một chiều vào mảng một chiều được
truyền vào bắt đầu từ vị trí chỉ ra.
GetLength Trả về số phần tử của một chiều được chỉ ra trên mảng
GetLowerBound Trả về chỉ số nhỏ nhất của một chiều được chỉ ra trên mảng
GetUpperBound Trả về chỉ số lớn nhất của một chiều được chỉ ra trên mảng
GetValue Trả về trị của một phần tử chỉ ra trên mảng
IndexOf Trả về chỉ số của phần tử đầu tiên trên mảng một chiều (hoặc trên một vùng
của mảng) trùng với giá trị truyền vào
LastIndexOf Trả về chỉ số của phần tử cuối cùng trên mảng một chiều (hoặc trên một vùng
của mảng) trùng với giá trị truyền vào
Reverse Đảo ngược thứ tự các phần tử trên mảng một chiều hoặc trên một phần của
mảng
SetValue Gán trị cho một phần tử chỉ ra trên mảng
Sort Sắp xếp các phần tử trong mảng một chiều
III.2. Structure
Khác với mảng, Structure, kiểu do người dùng định nghĩa (UDT: User Defined Type), là một cấu trúc
gồm một hoặc nhiều thành phần có kiểu dữ liệu khác nhau. Tuy chúng ta có thể truy xuất riêng lẻ các
thành phần nhưng Structure được xem như là một thực thể duy nhất. Trong phiên bản trước, UDT
được khai báo với từ khóa Type … End Type. Trong VB.NET, cú pháp khai báo Structure như sau:
Cú pháp:
Với Structure, chúng ta được phép khai báo các phương thức.
Sau đây là các đặc điểm của Structure:
Có các thành phần, kể cả bộ khởi tạo, phương thức, thuộc tính, hằng, sự kiện.
Có thể cài đặt các lớp giao tiếp (Interface).
Có thể có các bộ khởi tạo chung, có hoặc không có tham số.
Structure là kiểu trị.
Tất cả các thành phần của Structure mặc định là Public.
Các thành phần của Structure không được khai báo với từ khóa Protected.
Structure không thể kế thừa.
Mỗi Structure có một bộ khởi tạo mặc nhiên không tham số ban đầu. Bộ khởi tạo này sẽ khởi tạo mọi
thành phần dữ liệu của Structure với giá trị mặc định của chúng. Chúng ta không thể định nghĩa lại
chức năng này.
Vì Structure là kiểu trị (Value Type), nên mỗi biến Structure luôn luôn gắn liền với một thể hiện
Structure.
Ký hiệu Mô tả
= Bằng
>= Lớn hơn hoặc bằng
<= Nhỏ hơn hoặc bằng
> Lớn hơn
< Nhỏ hơn
<> Khác
TypeOf … Is … So sánh kiểu của biến kiểu tham chiếu thứ nhất có trùng kiểu trên toán hạng thứ
hai, nếu trùng trả về True, ngược lại False
Is Toán tử dành cho toán hạng kiểu tham chiếu, trả về True nếu hai toán hạng
cùng tham chiếu đến một đối tượng, ngược lại là False)
Like Toán tử dành cho toán hạng kiểu String, trả về True nếu toán hạng thứ nhất
trùng với mẫu (pattern) của toán hạng thứ hai, ngược lại là False.
Ví dụ:
Sử dụng cú pháp này, người lập trình muốn khai báo với trình biên dịch rằng các câu lệnh trong vùng If
… End If chỉ được thực hiện nếu như <điều kiện> là đúng.
<điều kiện> có thể là biểu thức trả về giá trị True/False hoặc là một giá trị số. Giá trị số <> 0 tương
ứng với True, ngược lại là False.
Cấu trúc If … Then … End If còn thiếu sót vì đôi khi chúng ta muốn thực hiện các câu lệnh khác khi
điều kiện không đúng. Lúc này, chúng ta sử dụng cấu trúc sau:
Cú pháp:
Trong trường hợp nhiều điều kiện, chúng ta sử dụng cấu trúc:
' Các lệnh thực hiện khi <biểu thức> không bằng giá trị nào ở trên
End Select
Khối lệnh Case Else có thể không cần viết. Tuy nhiên, người lập trình được khuyến khích dùng khối
lệnh này trong cấu trúc để giảm bớt các lỗi logic.
Các giá trị dùng để so sánh có thể gồm nhiều giá trị phân biệt bởi dấu phẩy (,) hoặc là một phần của
biểu thức so sánh.
For <biến đếm> = <giá trị đầu> To <giá trị cuối> [Step <bước>]
' Các câu lệnh
Next [biến đếm]
Các câu lệnh trong vùng For … Next chỉ được thực hiện nếu <biến đếm> có giá trị trong đoạn
[<giá trị đầu>, <giá trị cuối>]
Sau mỗi lần thực hiện, <biến đếm> sẽ được tăng thêm <bước>. Nếu không chỉ định, <bước> có
giá trị là 1.
Nếu <bước> có trị > 0, cấu trúc chỉ thực hiện khi <giá trị đầu> <= <giá trị cuối>
Nếu <bước> có trị < 0, cấu trúc chỉ thực hiện khi <giá trị đầu> >= <giá trị cuối>
Với cú pháp này, chương trình sẽ duyệt qua từng phần tử trong tập hợp đang duyệt.
Cần khai báo biến <phần tử> là kiểu của phần tử trong tập hợp đang duyệt. Chúng ta có thể chấm dứt
lặp khi đang giữa vòng lặp bằng lệnh Exit For
Với cú pháp này, các câu lệnh đặt trong vùng Do While … Loop chỉ thực hiện bao lâu <biểu thức logic>
có giá trị True.
Sau mỗi lần thực hiện các câu lệnh trong vùng Do While...Loop, <biểu thức logic> sẽ được kiểm tra lại:
Do
' Các câu lệnh
Loop While <biểu thức logic>
Tương tự Do While … Loop, các câu lệnh chỉ tiếp tục thực hiện khi <biểu thức logic> có giá trị True và
sẽ kiểm tra lại <biểu thức logic> sau mỗi lần thực hiện.
Do kiểm tra sau khi thực hiện nên nếu ngay lần đầu <biểu thức logic> có trị False, các lệnh cũng được
thực hiện một lần.
Chúng ta có thể chấm dứt giữa chừng vòng lặp với lệnh Exit Do
Do
' Các câu lệnh
Loop Until <biểu thức logic>
Hai cú pháp nầy tương tự hai cú pháp trên (Do While … Loop, Do … Loop While), với một khác biệt là
chỉ thực hiện hoặc tiếp tục thực hiện khi <biểu thức logic> là False.
Trong VB6, nếu tham số truyền vào là thuộc tính của một đối tượng cho thủ tục kiểu ByRef, những
thay đổi trên tham số đó trong thủ tục không phản ánh trên thuộc tính. Ngược lại, trong VB.NET, các
thay đổi như vậy đều thể hiện trên thuộc tính của đối tượng.
Option Strict On
--------------------------
Dim x As String, y As Integer
' x = y sẽ gây lỗi cú pháp
' nhưng phải dùng
x = CStr(y)
' hoặc
x = y.ToString
Cú pháp:
<chuỗi định danh>: bắt buộc, có giá trị kiểu String, là tiêu đề của khối lệnh
Ví dụ:
<bí danh>: tùy chọn, kiểu String, là tên tắt của <Namespace> được sử dụng trong tham chiếu trên
Module, Class. Nếu lệnh Imports không có phần bí danh, các thành phần định nghĩa trong không gian
tên có thể được truy cập mà không cần chỉ rõ. Nếu có bí danh, bí danh phải được sử dụng trong phần
truy cập.
<không gian tên>: bắt buộc, không gian tên sử dụng trong Module, Class
<thành phần>: tùy chọn, tên của một thành phần đã được khai báo trong không gian tên. Nó có thể là
định danh, structure, class…
Chú ý
Mỗi lệnh Imports chỉ được sử dụng với một không gian tên.
Mỗi Module có thể có nhiều dòng Imports
Các lệnh Imports phải được đặt trước tất cả các khai báo, kể cả lệnh khai báo Module hoặc Class.
Sau lệnh Imports, các thành phần được tham chiếu không cần phải chỉ ra nội dung phần Imports
Không được phép định nghĩa một thành phần ở cấp Module cùng tên với bí danh đã đặt
Ví dụ:
VII. Xử lý lỗi
VII.1. Phân loại lỗi
Trong VB.NET, chúng ta có thể gặp các loại lỗi sau:
VII.2. Xử lý lỗi
Một lỗi xảy ra khi chương trình đang chạy gọi là một Exception. Trong CLR, Exception là một đối tượng
từ lớp System.Exception. Chúng ta cần lưu ý một lỗi xảy ra trong lúc thực thi không làm treo chương
trình, nhưng nếu không được xử lý sẽ làm treo chương trình. CLR chỉ ra tình trạng lỗi qua lệnh Throw.
Lệnh này sẽ đưa ra một đối tượng kiểu System.Exception chứa thông tin về lỗi đang xảy ra.
Trước đây, chúng ta thường sử dụng cú pháp On Error Goto <nhãn lỗi> để xử lý lỗi. Đây là một loại xử
lý không cấu trúc vì kể từ dòng lệnh On Error Goto <nhãn lỗi> đến cuối thủ tục hay hàm, nếu dòng
lệnh nào gây lỗi chương trình đều nhường quyền xử lý cho đoạn lệnh của <nhãn lỗi>. Với VB.NET,
chúng ta phát hiện và xử lý lỗi một cách chặt chẽ với cú pháp
Cú pháp:
Try
' các lệnh có khả năng gây lỗi
Catch
' các lệnh xử lý khi lỗi xảy ra
[Finally]
' các lệnh thực hiện sau cùng
End Try
Cấu trúc này cho phép chúng ta thử (Try) thực hiện một khối lệnh xem có gây lỗi không; nếu có sẽ bẫy
và xử lý (Catch) lỗi.
Cấu trúc này chia làm các khối sau:
Khối Try:
Chứa các câu lệnh có khả năng gây lỗi
Khối Catch:
Các dòng lệnh để bẫy và xử lý lỗi phát sinh trên khối Try. Khối này gồm một loạt các lệnh bắt đầu
với từ khóa Catch, biến kiểu Exception ứng với một kiểu Exception muốn bẫy và các lệnh xử lý. Dĩ
nhiên, chúng ta có thể dùng một lệnh Catch cho các System.Exception, nhưng như thế sẽ không
cung cấp thông tin đầy đủ cho người dùng về lỗi đang xảy ra cũng như hướng dẫn cách xử lý cụ
thể cho mỗi tình huống. Ngoài những lỗi đã xử lý, có thể xảy ra những lỗi ngoài dự kiến, để xử lý
các lỗi này, chúng ta nên đưa thêm một lệnh Catch để bẫy tất cả các trường hợp còn lại và xuất
thông tin về lỗi xảy ra.
Khối Finally:
Khối tùy chọn, sau khi chạy qua các khối Try và Catch nếu không có chỉ định nào khác, khối Finally
sẽ được thực hiện bất kể có xảy ra lỗi hay không.
Cuối cùng, cấu trúc bẫy và xử lý lỗi chấm dứt với từ khóa End Try.
Cú pháp chung cho một cấu trúc xử lý lỗi như sau
Try
' khối lệnh có thể gây lỗi
Catch <biến1> As <Kiểu Exception> [When <biểu thức>]
' khối lệnh bẫy và xử lý lỗi
Catch <biến2> As <Kiểu Exception> [When <biểu thức>]
' khối lệnh bẫy và xử lý lỗi
Finally
' khối lệnh kết thúc
End Try
Ví dụ:
Catch ex As DivideByZeroException
Messagebox.Show(“Không thể chia cho số không”)
Catch ex As InvalidCastException
Messagebox.Show(“Xin nhập số nguyên !”)
End Try
Bài 3
LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
TRONG VISUAL BASIC .NET
Tóm tắt
Lý thuyết 6 tiết - Thực hành 10 tiết
Giới thiệu về Lập trình hướng đối 1. Lập trình hướng đối tượng 2.1, 2.2, 2.3, 2.4,
tượng và cách xây dựng lớp đối 2. Lập trình hướng đối tượng trong 2.5
tượng trong Visual Basic .Net VB.NET
Lập trình hướng đối tượng là kiểu lập trình nhằm vào sự tương tác giữa các đối tượng. Mỗi đối tượng
có những thuộc tính (thông tin lưu trữ), những phương thức xác định các chức năng của đối tượng.
Bên cạnh đó, đối tượng cũng có khả năng phát sinh các sự kiện khi thay đổi thông tin, thực hiện một
chức năng hay khi đối tượng khác tác động vào. Tất cả những thuộc tính, phương thức và sự kiện tạo
nên cấu trúc của đối tượng. Có bốn ý niệm trong Lập trình hướng đối tượng:
Abstraction: Tính trừu tượng
Encapsulation: Tính bao bọc
Inheritance: Tính kế thừa
Polymorphism: Tính đa hình
Mỗi ý niệm đều có vai trò quan trọng trong lập trình hướng đối tượng.
Ví dụ:
Xe hơi có các chức năng (phương thức phô diễn bên ngoài) như Ngừng, Chạy tới, Chạy lùi. Đây là
những gì cần thiết cho Tài xế khi tương tác với Xe hơi. Xe hơi có thể có một đối tượng Động cơ nhưng
Tài xế không cần phải quan tâm. Tất cả những gì cần quan tâm là những chức năng để có thể vận
hành xe. Do đó, khi thay một Động cơ khác, Tài xế vẫn sử dụng các chức năng cũ để vận hành Xe hơi
bao lâu các phương thức phô diễn bên ngoài (Interface) không bị thay đổi.
I.3.1. Là-một
Biểu thị tính kế thừa. Trong quan hệ "là-một", một đối tượng của lớp Con được xem như là một đối
tượng của lớp Cha.
Xe
Xe hơi
Ví dụ:
Từ lớp Xe ta tạo nên lớp Xe hơi mở rộng, lớp này mặc nhiên kế thừa tất cả các thành phần của lớp xe.
Ta có thể nói: một xe hơi là một chiếc xe.
I.3.2. Có-một
Quan hệ này mang ý nghĩa gồm có. Trong quan hệ "có-một", một đối tượng có thể có một hoặc nhiều
thành phần tham chiếu đến các đối tượng khác.
Ví dụ:
Khi lập mô hình loại xe hơi, bạn muốn diễn tả ý tưởng chiếc xe "có-một" tay lái. Chúng ta không thể
phát sinh lớp Xe hơi từ một Tay lái hay ngược lại (một Xe hơi "là-một" Tay lái !!!). Thay vì vậy, chúng
ta phải có hai lớp độc lập làm việc với nhau trong đó, lớp phía ngoài (lớp Xe hơi) sẽ tạo và phô diễn
công năng của lớp phía trong (lớp Tay lái).
Chúng ta có lớp Xe với phương thức Chạy và các lớp Xe đạp, Xe hơi, Xe đẩy cùng phát sinh từ lớp Xe.
Chúng ta chưa biết sẽ sử dụng xe gì để di chuyển vì tùy thuộc tình hình có sẵn xe nào nên gọi trước
phương thức Chạy. Khi chương trình thực thi, tùy theo đối tượng của lớp nào được đưa ra mà phương
thức Chạy của đối tượng đó được gọi.
Mã lệnh của Class nầy sẽ được chứa trong một tập tin có phần mở rộng là vb. Trong VB.NET tất cả các
tập tin nguồn của các đối tượng form, class, module …đều có phần mở rộng là vb. Hệ thống sẽ nhận
diện ra loại nào tùy theo nội dung của chúng chứ không dựa vào phần mở rộng.
Nhấn OK, để xác nhận tạo tập tin, tập tin sẽ được tạo và đưa vào Project. Lúc này trên cửa sổ mã lệnh
của Class chứa các dòng sau:
Mọi thuộc tính, phương thức hoặc sự kiện của Class được tạo ra phải nằm trong hai dòng lệnh trên.
Từ khóa có thể là một trong các giá trị ở bảng sau:
Namespace Dong_vat
Public Class An_co
End Class
Để tham chiếu đến một Class được khai báo trong Namespace, chúng ta phải thông qua tên
Namespace.
Ví dụ:
Một không gian tên có thể xuất hiện trong nhiều tập tin Class khác nhau trong một Project.
Ví dụ ta có tập tin thứ hai với nội dung:
Namespace Dong_vat
Public Class An_tap
End Class
End Namespace
Và cùng có chung cách tham chiếu thông qua không gian tên:
Chú ý: Lệnh Inherits phải là dòng đầu tiên sau dòng lệnh khai báo Class.
Cú pháp:
Tên Mô tả
Public Cho biết phương thức được gọi ở mọi nơi.
Protected Cho biết phương thức chỉ được gọi trong phạm vi của Class khai báo và các lớp
Con (Subclass)
Friend Cho biết phương thức chỉ được gọi trong phạm vi của Project
Protected Friend Cho biết phương thức chỉ được gọi trong phạm vi Proctected và Friend
Private Cho biết phương thức chỉ được gọi trong phạm vi của Class
Overloads Cho biết phương thức nạp chồng một hay nhiều phương thức có cùng tên với
phương thức trong lớp cơ sở. Danh sách tham số trong phương thức này phải
khác với danh sách tham số của mỗi phương thức nạp chồng khác về số lượng,
hoặc về các kiểu dữ liệu hoặc cả hai.
Chúng ta không cần phải dùng từ khóa Overloads khi tạo các phương thức nạp
chồng trong một lớp. Nhưng nếu đã khai báo cho một thì phải khai báo cho tất
cả.
Không được phép sử dụng cả hai từ khóa Overloads và Shadows trong cùng
một phương thức.
Ví dụ chúng ta có các lớp Tinh và Toan như sau:
Public Class Tinh
Function BP(ByVal so As Short) As Integer
Return so ^ 2
End Function
Function BP(ByVal so As Integer) As Long
Return so ^ 2
End Function
End Class
Public Class Toan
Inherits Tinh
Overloads Function BP(ByVal so As Double) As Double
Return so ^ 2
End Function
End Class
Các hàm BP trong lớp Tinh có thể có hoặc không có từ OverLoads
Một thể hiện của lớp Toan có thể sử dụng tất cả các hàm Overloads
Overrides Cho biết phương thức ghi chồng một phương thức cùng tên của lớp cơ sở. Số
lượng tham số, kiểu dữ liệu của tham số cũng như kiểu giá trị trả về phải khớp
với của lớp cơ sở.
Overridable Cho biết phương thức này cho phép ghi chồng bằng một phương thức cùng tên
trong lớp Con. Phương thức với từ khóa Overrides mặc nhiên là được phép ghi
chồng.
NotOverridable Cho biết phương thức không được phép ghi chồng trong lớp Con.
MustOverride Cho biết phương thức không được cài đặt trong lớp khai báo nhưng phải cài
đặt trong lớp Con.
Shadows Cho biết phương thức che lấp một thành phần có tên tương tự, hoặc một tập
hợp các thành phần nạp chồng của lớp cơ sở. Tham số và giá trị trả về không
nhất thiết phải như trong thành phần bị che. Thành phần bị che không còn giá
trị trong lớp che nó.
Không được phép sử dụng cả hai từ khóa Overloads và Shadows trong cùng
Shared Cho biết phương thức được dùng chung - nghĩa là phương thức này không liên
kết với một thể hiện nào của lớp. Chúng ta có thể gọi phương thức dùng chung
thông qua tên của lớp hoặc tên biến của một thể hiện cụ thể.
Ví dụ chúng ta có lớp TEST với một hàm Shared như sau:
Class TEST
Shared Function Cong(ByVal a As Integer, _
ByVal b As Integer) As Integer
Return a + b
End Function
End Class
Khi sử dụng, chúng ta có thể viết:
Dim y As TEST
Console.WriteLine(y.Cong(12, 9))
hoặc:
Console.WriteLine(TEST.Cong(12, 9))
' Khai báo biến lưu giữ giá trị của thuộc tính
Private mthuoctinh As <Kiểu dữ liệu>
II.5.1. Default
Khai báo thuộc tính mặc định. Các thuộc tính này phải có tham số và có thể gán và truy xuất không
cần chỉ ra tên thuộc tính.
Một thuộc tính chỉ có thể là thuộc tính mặc định nếu thỏa các điều kiện:
Mỗi Class chỉ được có một thuộc tính mặc định, phải kể đến cả các thuộc tính kế thừa.
Thuộc tính mặc định không được là Shared hay Private
Nếu một thuộc tính nạp chồng (Overloaded) là mặc định thì tất cả các thuộc tính cùng tên cũng
phải khai báo mặc định.
Thuộc tính mặc định phải có ít nhất một tham số
Cú pháp:
End Property
II.5.2. ReadOnly
Cho biết thuộc tính chỉ được phép đọc không cho phép gán.
Cú pháp:
II.5.3. WriteOnly
Cho biết thuộc tính chỉ được phép gán không cho phép đọc.
Cú pháp:
II.5.4. Overloads
Cho biết thuộc tính này nạp chồng một hoặc nhiều thuộc tính có cùng tên được định nghĩa trên lớp cơ
sở. Danh sách tham số trong thuộc tính này phải khác với danh sách tham số của mỗi thuộc tính nạp
chồng khác về số lượng, hoặc về các kiểu dữ liệu hoặc cả hai.
Chúng ta không cần phải dùng từ khóa Overloads khi tạo các thuộc tính nạp chồng trong một lớp.
Nhưng nếu đã khai báo cho một thì phải khai báo cho tất cả.
Không được phép sử dụng cả hai từ khóa sau một lượt: Overloads và Shadows trong cùng một thuộc
tính.
II.5.5. Overrides
Cho biết thuộc tính ghi chồng một thuộc tính cùng tên của lớp cơ sở. Số lượng tham số, kiểu dữ liệu
của tham số cũng như kiểu giá trị trả về phải khớp với của lớp cơ sở.
II.5.6. Overridable
Cho biết thuộc tính này được phép ghi chồng trong lớp Con.
II.5.7. NotOverridable
Cho biết thuộc tính không được phép ghi chồng trong lớp Con. Mặc nhiên, các thuộc tính là không
được phép ghi chồng.
II.5.8. MustOverride
Cho biết thuộc tính không được cài đặt trong lớp và phải được cài đặt ở lớp Con.
II.5.9. Shadows
Cho biết thuộc tính che lấp một thuộc tính có tên tương tự, hoặc một tập hợp các thuộc tính Nạp chồng
của lớp cơ sở. Tham số và giá trị trả về không nhất thiết phải như trong thuộc tính bị che. Thuộc tính bị
che không còn giá trị trong lớp che nó.
II.5.10. Shared
Cho biết thuộc tính được chia sẻ - nghĩa là thuộc tính không gắn chặt với một thể hiện nào của lớp
nhưng được sử dụng chung giữa các thể hiện của một lớp.
Các sự kiện trong VB.NET không hỗ trợ đúng nguyên tắc kế thừa. Một sự kiện khai báo trong Class nào
chỉ được phép gọi phát sinh sự kiện (RaiseEvent) chỉ trong lớp đó mà thôi, không được gọi phát sinh kể
cả trong các lớp kế thừa.
Cú pháp để gọi phát sinh sự kiện như sau
Cú pháp:
Ví dụ chúng ta có lớp Con_Nguoi và thuộc tính Chieu_Cao, khi chiều cao thay đổi sẽ phát sinh sự kiện
Chieu_Cao_Thay_doi như sau
Ví dụ:
Để sử dụng các sự kiện trên một biến, chúng ta sử dụng cú pháp sau khi khai báo biến:
Từ khóa WithEvents và Handles cung cấp cách khai báo các xử lý sự kiện. Các sự kiện do một đối
tượng phát sinh với từ khóa WithEvents có thể được xử lý bằng bất kỳ thủ tục nào được chỉ ra trong
mệnh đề Handles của sự kiện. Tuy mệnh đề Handles là cách thức chuẩn để kết hợp một sự kiện với
một xử lý sự kiện, nhưng lại giới hạn số các biến cố kết hợp với cùng xử lý sự kiện khi biên dịch.
Các lệnh AddHandler và RemoveHandler uyển chuyển hơn trong việc kết hợp sự kiện với xử lý sự kiện.
Chúng cho phép chúng ta linh hoạt kết hợp và ngắt rời các sự kiện với các xử lý sự kiện lúc thực thi và
chúng không đòi hỏi chúng ta phải khai báo biến với từ khóa WithEvents.
Với các sự kiện kết hợp với các form, control, Visual Basic .NET tự động phát sinh một xử lý sự kiện
rỗng và kết hợp với sự kiện.
Ví dụ khi chúng ta nhấp đúp vào một nút lệnh trên màn hình ở chế độ thiết kế, Visual Basic .NET tạo
một xử lý sự kiện kết hợp với sự kiện Click của nút lệnh như sau:
Hoặc chúng ta kết hợp các biến cố Click của các nút lệnh Button1, Button2 cho cùng một xử lý sự kiện
như sau:
Ví dụ:
II.7.2. Mybase
Từ khóa Mybase được dùng trong Class kế thừa, khi chúng ta muốn dùng các phương thức của chính
Class cơ sở.
Ví dụ:
Lớp lopCha với thủ tục Gioi_thieu và tạo tiếp Class lopCon kế thừa từ lopCha
Khi gọi phương thức Gioi_thieu của lopCon, chúng ta sẽ có hai thông báo: một của chính lopCon và
một của lopCha
Chú ý: Từ khóa Mybase
Chỉ được dùng để tham chiếu đến Class trung gian và các thành phần được kế thừa của nó.
Không phải là một đối tượng, nên thông thể gán trị, dùng làm tham số hoặc dùng trong toán tử
Is
Không được sử dụng trong các Standard Module.
II.7.3. MyClass
Từ khóa MyClass cho phép chúng ta gọi các phương thức Overridable của Class, dẫu các Class kế thừa
đã có các phương thức Overrides tương ứng.
Ví dụ:
Lớp lopCha với thủ tục Gioi_thieu và tạo tiếp Class lopCon kế thừa từ lopCha
Và một Class lopCon kế thừa từ lopCha có thủ tục Gioithieu ghi đè, và kế thừa thủ tục Chao của lopCha
End Class
Thì :
Cú pháp:
Thủ tục này không được có gì khác ngoài dòng khai báo. Thủ tục này được gọi là abstract method hay
pure virtual function, vì nó chỉ có phần khai báo không có phần định nghĩa. Trong các lớp kế thừa, các
thủ tục này buộc phải được cài đặt (Override) để sử dụng.
Kết hợp hai ý niệm MustInherit và MustOverride, chúng ta sẽ có Abstract Base Class. Đây là một Class
chỉ có khai báo không có phần cài đặt. Muốn dùng phải tạo class kế thừa, từ đó mới sử dụng được.
Ví dụ:
Lớp Abstract Base Class rất thích hợp để chúng ta tạo cái sườn hay bố cục của chương trình trong lúc
thiết kế. Tất cả những lớp kế thừa lớp Abstract Base Class đều phải cài đặt các thành phần đã khai báo
trong Abstract Base Class:
Ví dụ:
Các từ khóa có thể là Public, Friend, Protected, Protected Friend hoặc Private
Ví dụ:
Class nào tiếp nhận giao tiếp IChaohoi đều phải định nghĩa thủ tục Chao và Hoi_tham.
Một số yếu tố sau đây giúp xác định sử dụng Abstract Base Class hay Interface:
Nếu Class tạo ra, sẽ được kế thừa nhiều tầng sau đó, thì Abstract Class là giải pháp thích hợp.
Vì trong trường hợp này, nếu nâng cấp lớp cơ sở (base class), toàn bộ các lớp kế thừa từ nó sẽ
được tự động nâng cấp theo. Ngược lại, Interface không cho phép thay đổi sau khi đã tạo ra.
Nếu có yêu cầu thay đổi, chúng ta buộc phải tạo Interface mới hoàn toàn.
Nếu muốn chức năng tạo ra sẽ áp dụng cho nhiều nhóm đối tượng (Class) khác nhau, Interface
là thích hợp. Abstract Class chỉ áp dụng được cho một nhóm đối tượng liên quan mật thiết
nhau, trong khi Interface là cách thức thích hợp nhất cho các Class không có gì liên quan nhau.
Để thiết kế một số ít chức năng nhỏ, ngắn gọn, sử dụng Interface. Nếu thiết kế một bộ các
chức năng lớn, sử dụng Abstract Class.
Nếu muốn cung cấp một số chức năng đã được cài đặt sẵn cho các đối tượng, sử dụng Abstract
Class, vì nó cho phép cài đặt sẵn trong Abstract Class trong khi Interface không cho phép cài
đặt sẵn trên bất kỳ thành phần nào của nó.
MsgBox("Xe tu tu re trai")
End Sub
Sub Rephai()
MsgBox("Xe tu tu re phai")
End Sub
Sub Dithang()
MsgBox("Xe tiep tuc di thang")
End Sub
End Class
Sub Laixe(ByVal huong As Huonglai)
Select Case huong
Case Huonglai.trai
tlai.Retrai()
Case Huonglai.thang
tlai.Dithang()
Case Huonglai.phai
tlai.Rephai()
End Select
End Sub
End Class
hoặc
Lệnh Delegate định nghĩa các kiểu tham số và kiểu giá trị trả về của một lớp ủy quyền. Bất kỳ phương
thức nào có kiểu các tham số và kiểu trị trả về phù hợp đều có thể là một thể hiện của lớp ủy quyền
đó. Thủ tục sẽ được gọi thực hiện bằng cách gọi phương thức Invoke của lớp ủy quyền.
Mỗi lớp ủy quyền định nghĩa một bộ khởi tạo có tham số là một phương thức. Cách truyền thủ tục như
một tham số cho phương thức theo cú pháp:
Cú pháp:
Ví dụ:
Chúng ta có:
Một khai báo ủy quyền
Delegate Function Lon_Hon(ByVal so1 as Integer, ByVal so2 as Integer) as
Integer
Và hàm tìm số lớn nhất trong các số truyền vào như sau:
Function Lon_Nhat(ByRef Cacso() As Integer, ByVal sosanh As Lon_Hon) As
Integer
Dim i As Integer
Dim soMax As Integer = Cacso(0)
For i = 1 To Cacso.GetUpperBound(0)
soMax = sosanh(Cacso(i), soMax)
Next
Return soMax
End Function
Dim a() As Integer = New Integer() {107, 15, 9, 20, 34, 6, 100, 99, 10}
Console.Write("Số lớn nhất trong mảng là:" (0), _
Lon_Nhat(a, AddressOf Lay_so_lon))
Bài 4
TỔNG QUAN VỀ ADO.NET
Tóm tắt
Lý thuyết 1 tiết
Bài học này sẽ cung cấp cho học viên 1. Tổng quan
các kiến thức cơ bản và giới thiệu các 2. Kiến trúc ADO.NET
đối tượng trong ADO.NET.
3. Các đặc điểm của ADO .Net
4. Content Component
5. Managed Provider Component
I. Tổng quan
Hầu như bất kỳ ứng dụng nào cũng cần đến dữ liệu. Dữ liệu từ người dùng nhập vào, dữ liệu được lưu
trữ trong ứng dụng và dữ liệu từ các hệ thống khác,… tất cả đều là nguồn thông tin mà ứng dụng cần
xử lý với chức năng chính là hỗ trợ tìm kiếm, tính toán, thống kê và ra quyết định.
Để thực hiện các chức năng xử lý dữ liệu, người lập trình cần phải có các công cụ lập trình chuyên
dùng. Dữ liệu không đơn giản lưu trên các file văn bản hay file nhị phân với cấu trúc record do người
lập trình định nghĩa. Thay vào đó, hầu hết các ứng dụng tổ chức dữ liệu logic dựa trên cấu trúc cơ sở
dữ liệu quan hệ và lưu trữ vật lý dữ liệu dựa vào các hệ quản trị cơ sở dữ liệu quan hệ như Access, SQL
Server, Oracle, DB2,…
Khi dữ liệu trở thành trung tâm của ứng dụng thì việc cung cấp các chức năng tới người dùng phụ
thuộc vào khả năng xử lý và thao tác với dữ liệu. Vấn đề mà người thiết kế và xây dựng ứng dụng
quan tâm khi làm việc với dữ liệu là:
Lưu trữ dữ liệu tập trung
Đảm bảo toàn vẹn dữ liệu
Đảm bảo khả năng truy xuất đồng thời của nhiều người dùng trên dữ liệu
Đảm bảo thời gian hồi đáp ngắn cho mỗi người dùng
Bảo mật dữ liệu
Trao đổi dữ liệu giữa các hệ thống khác nhau
Những vấn đề này được giải quyết nhờ vào khả năng của các hệ quản trị cơ sở dữ liệu (HQT CSDL) và
cách phần mềm xử lý dữ liệu do hệ quản trị dữ liệu cung cấp. Với các database server sử dụng HQT
CSDL như Oracle, SQL Server,… dữ liệu được đảm bảo lưu trữ tập trung, toàn vẹn và truy xuất đồng
thời cũng như bảo mật. Tuy nhiên, thời gian hồi đáp người dùng và trao đổi dữ liệu phụ thuộc hoàn
toàn vào các phần mềm. Với các công cụ lập trình xử lý dữ liệu như ADO (Active Data Object),
Microsoft đem lại cho người lập trình một công cụ rất tự nhiên khi thực hiện các thao tác trên dữ liệu.
ADO được cải tiến liên tục trong các phiên bản hệ điều hành Windows hay MS Office. Tuy nhiên, với sự
ra đời của .NET, ADO không còn là thành phần Component độc lập nhưng gắn liền với .NET Framework
để cung cấp các dịch vụ xử lý dữ liệu.
ADO.NET có nhiều đổi mới so với ADO nhằm hướng tới người dùng nhiều hơn là người lập trình. Cấu
trúc mới của ADO.NET hơi gượng ép với người lập trình khi làm việc với dữ liệu nhưng lại nhằm cung
cấp khả năng truy xuất và xử lý dữ liệu lớn, đồng thời trên hệ thống ứng dụng phân tán nhiều người
dùng.
Đặc điểm chính của ADO.NET là làm việc với dữ liệu không kết nối. Dữ liệu được lưu trữ trong bộ nhớ
như một CSDL thu nhỏ gọi là DataSet, nhằm tăng tốc độ tính toán, xử lý tối đa và hạn chế việc sử
dụng tài nguyên trên Database Server. Đặc điểm quan trọng thứ hai là khả năng xử lý dữ liệu dạng
chuẩn XML. Dữ liệu ở dạng XML có thể trao đổi giữa bất kỳ hệ thống nào nên ứng dụng của bạn sẽ có
nhiều khả năng làm việc với nhiều ứng dụng khác.
Sau dây, chúng ta sẽ xem xét phần tổng quan kiến trúc của ADO.NET cùng với các kỹ thuật lập trình cơ
bản.
Managed Provider Component: bao gồm các đối tượng như DataAdapter, DataReader,… giữ
nhiệm vụ làm việc trực tiếp với dữ liệu như database, file,…
Content Component: bao gồm các đối tượng như DataSet, DataTable,… đại diện cho dữ liệu thực
sự cần làm việc. DataReader là đối tượng mới, giúp truy cập dữ liệu nhanh chóng nhưng forward-
only và read-only giống như ADO RecordSet sử dụng Server cursor, OpenFowardOnly và
LockReadOnly.
DataSet cũng là một đối tượng mới, không chỉ là dữ liệu, DataSet có thể coi là một bản sao gọn nhẹ
của CSDL trong bộ nhớ với nhiều bảng và các mối quan hệ.
DataAdapter là đối tượng kết nối giữa DataSet và CSDL, nó bao gồm 2 đối tượng Connection và
Command để cung cấp dữ liệu cho DataSet cũng như cập nhật dữ liệu từ DataSet xuống CSDL.
Trong ví dụ sau, chúng ta sẽ sử dụng điều khiển DataGrid để hiển thị dữ liệu từ bảng DMCV trong
C:\QL_NHAN_SU\CSDL\Qlns.mdb.
Ví dụ:
Chúng ta có:
Với đoạn lệnh trên, chúng ta thấy cách lập trình của ADO.NET tương đối giống với ADODB thông
thường, đó là trước tiên cần kết nối với CSDL bằng một đối tượng Connection. Dữ liệu sẽ được quản lý
bởi một đối tượng, đó là DataSet như bạn thấy trong sơ đồ cấu trúc của ADO.NET.
Cũng trong sơ đồ này, bạn thấy rằng một DataAdapter có một Connection và nhiều đối tượng
Command. Trong ví dụ của chúng ta bạn thấy rõ điều này: bo_doc_ghi được tạo mới với một
connection là Ket_noi và một Select Command.
Đối tượng DataSet không làm việc trực tiếp với CSDL mà thông qua DataAdapter. Do đó, để DataSet có
dữ liệu, bạn phải dùng phương thức Fill của bo_doc_ghi lấy dữ liệu từ Qlns.mdb thông qua connection
Ket_noi đổ vào một bảng trong DataSet ds. Cuối cùng, để hiển thị dữ liệu chúng ta thực hiện việc liên
kết điều khiển với nguồn dữ liệu (Binding): kết nối Luoi_cong_viec với bảng "CONG_VIEC" trong ds.
Với ADO, Disconnected RecordSet được đóng gói ở dạng Network Data Representation (NDR)
trước khi truyền trên mạng. NDR vẫn là dạng đối tượng mà ở tầng Application, data provider và
data consumer phải sử dụng kỹ thuật COM để xử lý.
ADO.NET thay thế NDR bằng định dạng mới: XML. Với bản chất Text, XML hoàn toàn có thể sử
dụng HTTP để trao đổi dữ liệu. Hơn nữa XML document dễ dàng được xử lý mà không cần đến
kỹ thuật COM. XML là chuẩn để trao đổi dữ liệu mới nhất và đang được hỗ trợ rất rộng rãi.
Với ADO.NET, có sự tập trung rõ ràng hơn về các chức năng của các đối tượng. Ví dụ, Connection
không còn lo việc thi hành một câu lệnh SQL hay một Stored Procedure nữa, công việc này được giao
hoàn toàn cho Command đảm nhận.
Đáng chú ý hơn, ADO.NET phát triển trên .NET là component có thể kế thừa được. Người lập trình
hoàn toàn có khả năng kế thừa các đối tượng của ADO.NET để xây dựng các đối tượng mới tốt hơn và
phù hợp với nhu cầu phát triển ứng dụng của mình.
Cuối cùng, Visual Studio .NET với Component Designer giúp người lập trình tạo ra các DataSet nhanh
chóng với nội dung lệnh rõ ràng hơn những gì Data Form Wizard của Visual Studio 6 trước đây tạo ra.
Disconnected data đảm bảo ứng dụng trên Client ít gặp lỗi khi xử lý dữ liệu đồng thời giúp mở
rộng ứng dụng tới nhiều người dùng hơn. Các managed provider component hỗ trợ tính năng
thiết lập connection pooling ngầm định để giảm bớt thời gian tái kết nối.
Định dạng XML thay thế cho NDR trong trao đổi dữ liệu giữa Server và Client giúp cho dữ liệu
có thể được xử lý bởi nhiều client hơn dù ứng dụng trên Client có hay không sử dụng COM. XML
cũng giúp việc truyền thông nhanh hơn vì không cần đóng gói phức tạp như NDR hay chuyển
qua chuyển lại giữa dữ liệu thô sang dữ liệu ở dạng đối tượng.
DataTableCollection
DataTable
DataRowCollection
«DataRow
DataColumnCollection
DataColumn
DataView
DataRelationCollection
DataRelation
Content Component
IV.1. DataSet
Với ADO, dữ liệu chứa trong RecordSet cho dù chúng được lấy từ một hay nhiều bảng. Vì ADO không
có cách nào mô tả mối quan hệ giữa các bảng trong CSDL với nhau, cách duy nhất để lấy dữ liệu từ
nhiều bảng là viết các câu truy vấn SQL kết giữa các bảng với nhau.
ADO.NET chứa dữ liệu trong DataSet cùng với mối quan hệ giữa các dữ liệu đó. DataSet giống như một
hình ảnh về CSDL trong bộ nhớ, có thể có nhiều DataTable và các mối quan hệ giữa chúng đại diện bởi
các DataRelation.
Vì DataSet dùng cơ chế disconnected data, cần có chức năng giúp kiểm soát các thay đổi về dữ liệu đã
xảy ra và cập nhật những thay đổi đó xuống CSDL. Các chức năng được thực hiện qua các phương
thức:
HasChanges()
HasErrors()
GetChanges()
AcceptChanges()
RejectChanges()
Người lập trình có thể sử dụng các phương thức (hoặc hàm) này để kiểm tra sự thay đổi trên DataSet,
tập hợp những thay đổi đó vào một DataSet khác, tìm các lỗi và sau đó chấp nhận cập nhật hay bỏ qua
những thay đổi.
Sơ đồ đối tượng trên đây minh hoạ các đối tượng trong tập hợp Content Component và sự liên quan
giữa các đối tượng đó.
IV.2. DataTable
Là một thành phần trong DataSet, DataTable chứa dữ liệu của một bảng trong DataSet và thuộc lớp
DataTable. DataTable bao gồm:
Tập hợp Columns thuộc lớp DataColumnCollection trong đó mỗi cột là một đối tượng thuộc lớp
DataColumn
Tập hợp Rows thuộc lớp DataRowCollection trong đó mỗi dòng là một đối tượng thuộc lớp
DataRow.
IV.3. DataRelation
DataSet bao gồm tập hợp các table đại diện bởi các đối tượng DataTable và quan hệ giữa các table đó
đại diện bởi các đối tượng DataRelation.
Với DataRelation, người lập trình có thể:
Định nghĩa được mối quan hệ giữa các bảng
Duyệt dữ liệu trong các bảng theo kiểu Master – Detail
Một đối tượng kiểu DataRelation bao gồm các thông tin:
ForeignKeyConstraint: chỉ ra cách ứng dụng sẽ thực hiện khi cập nhật hay xoá dữ liệu trên bảng
có quan hệ với bảng khác. Các giá trị của ForeignKeyConstraint:
+ None: không làm gì cả
+ Cascade: phụ thuộc vào dòng trên parent table sẽ bị cập nhật hay xoá
+ SetDefault: giá trị của cột khoá ngoại trên detail table được đặt về giá trị mặc định khi dòng
trên parent table bị xoá
+ SetNull: Giống SetDefault, giá trị được đặt là Null
IV.5. DataView
DataView gần giống với khái niệm RecordSet của ADO. Trên một DataTable có thể tạo nhiều DataView
với các điều kiện lọc, sắp xếp dữ liệu khác nhau. Trên DataView ta có thể xem hay thay đổi giá trị các
mẩu tin.
DataView của ADO.NET còn giữ nhiệm vụ kết nối với các control của Window Form và Web Form.
IDBConnection IDBCommand
IDBParameterCollection
OleDBParameterCollection SQLParameterCollection
IDataReader DataAdapter
V.1. Connection
Cả OleDBConnection và SQLConnection đều có các thuộc tính và phương thức giống nhau như
ConnectionString, State hay Open.
Nói chung Connection của ADO.NET và ADO đều có cách sử dụng tương tự nhau ngoại trừ:
Connection của ADO.NET không thể thực hiện các câu truy vấn hay các stored procedure vì
không còn phương thức Execute nữa.
Connection của ADO.NET không còn hỗ trợ Transaction. Với ADO.NET, một transaction được
quản lý bởi đối tượng OleDBTransaction hoặc SQLTransaction (cả hai đều implement
IdbTransaction). Đối tượng Transaction hỗ trợ các phương thức như Commit và Rollbacks.
SQLTransaction còn hỗ trợ các checkpoint trong quá trình rollback.
Các provider mà OLEDB và SQL có thể dùng để kết nối dữ liệu là:
SQLOLEDB: OLEDB Provider của Microsoft cho SQL Server
MSDAORA: OLEDB provider của Microsoft cho Oracle
JOLT: OLEDB provider cho Jet.
V.2. Command
Đối tượng Command vẫn có cùng cách sử dụng như Command của ADO. Thuộc tính Connection của
SQLCommand hoặc OleDBCommand chỉ ra kết nối với CSDL sẽ sử dụng. Command cũng có thể sử
dụng các tham số để thi hành các stored procedure.
Sơ đồ ở hình trên cho thấy mối liên hệ giữa Command với Connection và DataReader. Command trong
ADO.NET có các cách thức thực hiện lệnh là:
ExecuteReader(): dùng đề thực hiện các câu truy vấn trả về dữ liệu. Dữ liệu trả về sẽ là một đối
tượng DataReader hoặc một đối tượng nào đó có implement IdbReader interface.
ExecuteNonQuery(): dùng để thực hiện các lệnh cập nhật dữ liệu.
ExecuteScalar(): dùng để thực hiện các lệnh tính toán và trả về một dòng, một cột chứa kết quả
của lệnh tính toán.
V.3. DataReader
DataReader thực sự là một đối tượng tương tự với RecordSet của ADO ngoại trừ khả năng giới hạn của
nó là ReadOnly lock và ForwardOnly cursor. Một DataReader được tạo ra bằng cách thực hiện phương
thức ExecuteReader của đối tượng Command.
DataReader hỗ trợ về mặt tốc độ khi truy cập dữ liệu, tuy nhiên nó sử dụng cursor ở phía Server và kết
nối với Server trong suốt quá trình đọc dữ liệu. Việc này khác với cơ chế sử dụng Disconnect data của
ADO.NET và giảm khả năng mở rộng của ứng dụng. Vì vậy khi đã có một đối tượng DataReader, cần
phải tiến hành việc đọc dữ liệu càng nhanh càng tốt.
Sử dụng Connection kết hợp với Command và DataReader là một cách được coi là "low level" của
ADO.NET để thao tác với dữ liệu. ADO.NET cung cấp DataAdapter là một kết hợp của Connection với
các Command giúp kết nối DataSet với database trên Server.
V.4. DataAdapter
DataAdapter được ADO.NET cung cấp như một công cụ giúp kết nối dữ liệu của một table trong
DbDataAdapter
OleDBDataAdapter SQLDataAdapter
DataAdapter
Hình trên mô tả mô hình phân cấp các class của DataAdapter, cả SQLDataAdapter và
OleDBDataAdapter đều thừa kế từ class DbDataAdapter, DbDataAdapter lại thừa kết từ abstract class
DataAdapter, đến lượt abstract class này lại implement IDataAdapter interface để hỗ trợ hai phương
thức Fill và Update.
Để lấy dữ liệu cho một table trong DataSet, sử dụng phương thức Fill(), để cập nhật dữ liệu cho
DataSet, sử dụng phương thức Update().
Để lấy dữ liệu, DataAdapter dùng SELECT query thông qua thuộc tính SelectCommand. Để cập
nhật dữ liệu, DataAdapter dùng các câu query UPDATE, INSERT, DETETE thông qua các thuộc
tính UpdateCommand, InsertCommand và DeleteCommand.
Ngoài Fill và Update, DataAdapter còn kế thừa thuộc tính TableMappings giúp cung cấp cho người dùng
các tên table và tên column dễ đọc hơn các tên thực được sử dụng trong Database.
Trong các đối tượng Command của DataAdapter, chỉ có đối SelectCommand là bắt buộc, các đối tượng
còn lại đều có thể tự động được phát sinh.
Hình dưới đây mô tả quan hệ giữa các đối tượng thuộc Managed Provider Components.
Command Exception
Connection ErrorCollection
ParameterCollection Error
Parameter
DataReader
DataAdapter
SelectCommand
InsertCommand
DeleteCommand
UpdateCommand
DataTableMappingCollection
DataTableMappingCollection
DataColumnMappingCollection
DataColumnMapping
Bài 5
CONNECTION, COMMAND,
DATAADAPTER
Tóm tắt
Lý thuyết 2 tiết - Thực hành 5 tiết
Kết thúc bài học này, học viên có thể 1. Connection 3.1, 3.2
làm việc với dữ liệu thông qua các đối 2. Command
tượng ADO.NET
3. DataAdapter
I. Connection
Vai trò của Connection trong ADO.NET cũng như trong ADO là tạo kết nối giữa ứng dụng và nguồn dữ
liệu. Điểm khác biệt chính là ADO.NET không còn hổ trợ các thao tác dữ liệu có kết nối. Mặt khác,
Connection trong ADO.NET giờ đây chỉ đóng vai trò tạo kênh thông tin giữa ứng dụng và CSDL, không
thực hiện các lệnh truy xuất, cập nhật CSDL như trong ADO.
Connection
CSDL
Imports SysTem.Data.OleDb
…
Dim ket_noi As New OleDbConnection()
I.2. ConnectionString
Trước khi thực hiện kết nối, cần khai báo các thông tin cần thiết cho Connection thông qua thuộc tính
ConnectionString. Cách khai báo thay đổi tùy thuộc Data Provider. Với OLEDB Provider có thể gồm các
thành phần
Provider: Khai báo Data Provider
Imports SysTem.Data.OleDb
Dim chuoi_kn As String = "Provider=Microsoft.Jet.OLEDB.4.0; " & _
"Data Source =" & <đường dẫn>
Dim cnn As New OleDbConnection(chuoi_kn)
Imports SysTem.Data.OleDb
Dim chuoi_kn As String = "Provider=SQLOLED;User ID=" & <người dùng> & _
";Password =" & <mật khẩu> & ";Data Source=" & <tên hoặc TCP/IP server> _
& ";Initial Catalog =" & <tên Database>
Dim cnn As New OleDbConnection(chuoi_kn)
Imports SysTem.Data.OleDb
Dim chuoi_kn As String = "Provider=MSDAORA.1;User ID=" & <người dùng> & _
";Password =" & <mật khẩu> & ";Data Source=" & <đường dẫn>
Dim cnn As New OleDbConnection(chuoi_kn)
SqlConnection chỉ cho phép kết nối đến dữ liệu SQL Server từ phiên bản 7.0 trở về sau. Cách khai báo
khác hơn với các thành phần chính như sau:
Data Source: Tên máy nơi cài đặt SQL Server có nguồn dữ liệu muốn kết nối
Initial Catalog: Tên database muốn kết nối
Integrated Security : True(SSPI)/ False chỉ định dùng cơ chế bảo mật của Windows Login (True)
hay cơ chế bảo mật của SQL Server (False)
User ID: Tên người dùng (phải khai báo khi Integrated Security = False)
PassWord: Mật khẩu (phải khai báo khi Integrated Security = False)
Việc sử dụng cơ chế bảo mật nào tùy thuộc SQL Server qui định.
Ví dụ: Tạo Connection đến CSDL SQL Server sử dụng SqlConnection
Imports SysTem.Data.SqlClient
Dim chuoi_kn As String = "Data Source=" & <địa chỉ TCP/IP hay tên máy> & _
"Initial Catalog=" & <tên database> & _
";User ID =" & <tên người dùng> & ";Password =" & <mật khẩu>
Dim cnn As New SqlConnection(chuoi_kn)
Hoặc
Imports SysTem.Data.SqlClient
Dim chuoi_kn As String = "Data Source=" & <địa chỉ TCP/IP hay tên máy> & _
"Initial Catalog=" & <tên database> & ";Integrated Security =SSPI"
Imports System.Data.Oledb
…
Dim chuoi_kn As String = "Provider =Microsoft.Jet.OLEDB.4.0; " & _
II. Command
Sau khi tạo kết nối với nguồn dữ liệu, mọi thao tác trên nguồn dữ liệu đó đều được thực hiện thông
qua Command. Tùy theo loại Connection, đối tượng Command thuộc không gian tên như sau:
System.Data.OleDb.OleDbCommand
System.Data.SqlClient.SqlCommand
Hoặc
Hoặc
Hoặc
CommandText là tên của một bảng. Khi Command thực hiện sẽ trả về
đủ các dòng và các cột (chỉ dùng cho OledbCommand)
Ví dụ:
Imports Systm.Data.Oledb
…
Dim chuoi As String ="Provider=SQLOLEDB; " & _
"Integrated Security = SSPI; " & _
"Initial Catalog=DAT_GIAO;Data Source=HUUTHIEN"
Dim cnn As New OleDbConnection(chuoi)
cnn.Open()
Dim lenh As New OleDbCommand("PHIEU_NHAP",cnn)
lenh.CommandType = CommandType.TableDirect
II.3. Parameter
Lệnh SQL trong CommandText có thể sử dụng các dấu hỏi (?) thay thế cho trị chưa xác định và khi
thực hiện sẽ dùng đối tượng Parameter để truyền giá trị vào chỗ các dấu hỏi. Tùy theo Command,
Parameter sẽ khai báo từ lớp OledbParameter hay SqlParameter.
Cú pháp:
OleDbType Kiểu dữ liệu OleDb hoặc SqlDb của tham số. (đọc ghi)
SqlDbType
ParameterName Tên tham số. (đọc ghi)
Value Giá trị của tham số. (đọc ghi)
Để đưa một tham số cho Command, chúng ta có thể sử dụng một trong các cách sau:
lenh.CommandText = "Select * from CTNHAP where sopn = @sp and mavtu = @vt"
‘ thứ tự đưa tham số vào tùy ý vì phải chỉ đúng tên tham số trong lệnh SQL
Dim ts1 As SqlClient.SqlParameter = lenh.Parameters.Add("@vt", _
SqlDbType.Char, 4)
ts1.Value = "S001"
Dim ts2 As SqlClient.SqlParameter = lenh.Parameters.Add("@sp", _
SqlDbType.Char, 4)
ts2.Value = "PN01"
lenh.CommandText = "spSLGiao"
lenh.CommandType = CommandType.StoredProcedure
Dim tv As New OleDbParameter()
tv.Direction = ParameterDirection.ReturnValue
tv.OleDbType = OleDb.OleDbType.Integer
lenh.Parameters.Add(tv)
Dim ts1 As OleDbParameter = lenh.Parameters.Add("@sodh", _
OleDbType.Char, 4)
ts1.Value = "D001"
Dim ts2 As OleDbParameter = lenh.Parameters.Add("@mavtu", _
OleDbType.Char, 4)
ts2.Value = "C001"
II.4.1. ExecuteNonquery
Để gọi thực hiện các câu truy vấn cập nhật INSERT, UPDATE, DELETE,... hay thủ tục nội không trả về
dữ liệu hoặc khi chúng ta không quan tâm đến dữ liệu trả về. Tuy không trả về dữ liệu, nhưng các
tham số đầu ra, trả về đều chứa dữ liệu (nếu có). Với các lệnh INSERT, UPDATE, DELETE, phương thức
này trả về số dòng chịu tác động của Command, ngược lại phương thức trả về -1:
Ví dụ: Trong ví dụ trên, chúng ta nhận được số lượng mặt hàng "C001" đã giao cho đơn đặt hàng
“D001” khi goi thực hiện như sau.
cmd.ExecuteNonQuery()
Console.WriteLine("Số lượng đã giao {0}", tv.Value)
II.4.2. ExecuteReader
Phương thức này trả về một đối tượng DataReader để đọc dữ liệu mỗi lần một dòng với phương thức
Read(). DataReader đọc dữ liệu trực tiếp từ nguồn dữ liệu nên phải duy trì kết nối cho đến khi đọc
xong. Cú pháp gọi phương thức này như sau.
Cú pháp:
ExecuteReader()
Hoặc
ExecuteReader(<behavior>)
For i = 0 To bo_doc.FieldCount -1
ndung &= bo_doc.GetValue(i) & vbTab
Next
ndung &= vbNewLine
Loop
bo_doc.Close()
MsgBox (lenh.Connection.State) ' trả về Closed
II.4.3. ExecuteScalar
Phương thức này thực hiện lệnh của Command và chỉ trả về giá trị của cột đầu tiên và dòng đầu tiên.
Chúng ta thường gọi phương thức này khi muốn Command thực hiện các hàm tính toán thống kê SUM,
COUNT, AVG, MAX, MIN, ... trên nguồn dữ liệu ngay lúc thực thi.
Cú pháp:
ExecuteScalar()
Ví dụ:
II.5. DataReader
Là đối tượng truy cập dữ liệu trực tiếp, sử dụng cursor phía Server và duy trì kết nối với Server trong
suốt quá trình đọc dữ liệu, DataReader thuộc không gian tên System.Data.OledbDataReader hoặc
System.Data.SqlDataReader
Trong khi DataReader đang mở, các thao tác dữ liệu khác trên nguồn dữ liệu đều không thể cho đến
khi DataReader đóng lại bằng lệnh Close.
III. DataAdapter
Để lấy dữ liệu từ nguồn dữ liệu về cho ứng dụng, chúng ta sử dụng một đối tượng gọi là DataAdapter.
Đối tượng này cho phép lấy cấu trúc và dữ liệu của các bảng trong nguồn dữ liệu.
DataAdapter là một bộ gồm bốn đối tượng Command:
SelectCommand: cho phép lấy thông tin từ nguồn dữ liệu về
InsertCommand: cho phép thêm dữ liệu vào bảng trong nguồn dữ liệu.
UpdateCommand: cho phép sửa đổi dữ liệu trên bảng trong nguồn dữ liệu.
DeleteCommand: cho phép hủy bỏ dữ liệu trên bảng trong nguồn dữ liệu.
Thông thường, chúng ta chỉ cần khai báo nội dung lệnh cho SelectCommand, các nội dung của các
command còn lại có thể được phát sinh nhờ đối tượng CommandBuilder dựa vào nội dung của
SelectCommand.
System.Data.OleDb.OleDbDataAdapter
System.Data.SqlClient.SqlDataAdapter
Cú pháp:
New <loại>DataAdapter()
New <loại>DataAdapter(<đối tượng SelectCommand>)
<đối tượng SelectCommand>: Đối tượng Command có sẵn với nội dung lệnh truy xuất.
<lệnh>: Câu lệnh SQL, tên storedprocedure… để thực hiện truy xuất từ nguồn dữ liệu
<đối tượng Connection>: Đối tượng Connection, trên đó DataAdapter thao tác với nguồn dữ liệu
Hoặc
Hoặc
Hoặc
Tên Mô tả
ContinueUpdateOnError Chỉ định cách thức xử lý khi DataAdapter cập nhật dữ liệu về nguồn và bị
lỗi. Nếu là True, DataAdapter bỏ qua dòng bị lỗi và cập nhật các dòng kế
tiếp. Lỗi phát sinh sẽ được đưa vào thuộc tính RowError của dòng bị lỗi,
ngược lại False, sẽ phát sinh Exception khi dòng bị lỗi.
DeleteCommand Đối tượng Command chứa nội dung lệnh hủy các mẩu tin trên nguồn dữ
liệu.
InsertCommand Đối tượng Command chứa nội dung lệnh chèn các mẩu tin mới vào nguồn
dữ liệu.
SelectCommand Đối tượng Command chứa nội dung lệnh truy xuất các mẩu tin từ nguồn
dữ liệu.
TableMappings Tập hợp các ánh xạ tên bảng khi DataAdapter đổ dữ liệu hay cấu trúc vào
đối tượng chứa.
UpdateCommand Đối tượng Command chứa nội dung lệnh cập nhật các mẩu tin vào nguồn
dữ liệu.
Fill(<datatable>)
Đổ dữ liệu vào DataSet có sẵn. Dữ liệu được lấy về Dataset dưới dạng các DataTable, với tên mặc định
là Table,Table1,Table2,…
Fill(<dataset>)
Đổ dữ liệu vào DataSet cho bảng <tên Datatable>; nếu chưa có, bảng sẽ được tạo
Kinh nghiệm giảng dạy:
Khi dùng nhiều DataAdapter để đổ dữ liệu của nhiều bảng vào DataSet, nếu không chỉ
rõ đổ vào bảng nào trong DataSet, dữ liệu sẽ đổ chung vào một bảng, số cột là tổng số
cột có tên khác nhau trong các bảng từ nguồn dữ liệu, trên mỗi dòng cột nào không có
dữ liệu tương ứng sẽ mang trị Null.
Kinh nghiệm giảng dạy:
Chúng ta có
thể dùng
một
DataAdapter
để đổ dữ
liệu của
nhiều bảng
từ SQL
Server vào
DataSet với
nội dung
lệnh truy
vấn là các
lệnh liên
tiếp và cách
nhau bằng
dấu (;)
Ví dụ:
Học phần 3 – VB.NET Trang 100/187
Tài liệu hướng dẫn giảng dạy
Với lệnh Fill như trên (không có tên bảng), dữ liệu đổ về DataSet dưới hình thức các DataTable có tên
lần lượt Table, Table1,…
bo_doc_ghi.Fill(dst, "Vattu")
Dữ liệu đổ về DataSet dưới hình thức các DataTable có tên lần lượt Vattu, Vattu1,…
Để đặt lại tên cho các bảng, chúng ta có thể dùng cách ánh xạ tên bảng như sau trước khi đổ dữ liệu:
Cho trường hợp không có tên bảng (sử dụng bo_doc_ghi.Fill(dst))
Tạo cấu trúc dữ liệu cho DataTable có sẵn, phương thức trả về DataTable
Tạo cấu trúc dữ liệu cho bảng <tên Datatable> trong DataSet; nếu chưa có, bảng sẽ được tạo ra
<kiểu cấu trúc>: Qui định việc ánh xạ tên có được chấp nhận hay không.
Khi sử dụng giá trị SchemaType.Source, bo_doc_ghi sẽ lấy cấu trúc về cho các bảng trong DataSet và
đặt tên các bảng theo cách mặc nhiên Table, Table1
bo_doc_ghi.FillSchema(dst,SchemaType.Source)
Khi sử dụng giá trị SchemaType.Mapped, bo_doc_ghi sẽ lấy cấu trúc về cho các bảng trong DataSet và
đặt tên các bảng lần lượt theo TableMappings đã tạo: Vattu, Nhac
bo_doc_ghi.FillSchema(dst,SchemaType.Mapped)
System.Data.Oledb.OledbCommandBuilder
System.Data.SqlClient.SqlCommandBuilder
Ví dụ:
Imports System.Data.Oledb
…
Dim chuoi As String = "Provider = Microsoft.Jet.OLEDB.4.0; " & _
"Data Source = C:\QlHanghoa.mdb"
Dim bo_doc_ghi As New OledbDataAdapter("Select * from VATTU", chuoi)
Dim bo_phat_sinh As New OledbCommandBuilder(bo_doc_ghi)
Mỗi DataAdapter chỉ có thể kết hợp với một CommandBuilder. Đối tượng này dùng nội dung lệnh trong
SelectCommand của DataAdapter để tạo nội dung lệnh cho các Command còn lại với các đặc điểm sau:
CommandBuilder chỉ phát sinh nội dung lệnh cập nhật cho các DataAdapter có nội dung
SelectCommand truy xuất đến chỉ một bảng nguồn
Nội dung trong SelectCommand phải có ít nhất một khóa chính hoặc một khóa duy nhất
(Unique key) để DataAdapter phân biệt các dòng khi cập nhật. Nếu không, CommandBuilder sẽ
không phát sinh được nội dung lệnh cho các Command Insert, Update, Delete.
Trường hợp nội dung của SelectCommand là truy vấn từ hơn một bảng hoặc từ một
StoredProcedure, các Command cập nhật không tự động phát sinh, nhưng chúng ta phải khai
báo các Command cập nhật cách tường minh.
Sau khi lệnh được phát sinh, nếu nội dung lệnh của SelectCommand thay đổi, lệnh của các
Command khác không tự động thay đổi theo cho đến khi phương thức RefreshSchema của
CommandBuilder được gọi.
Trường hợp nội dung của SelectCommand là nhiều câu Select SQL, CommandBuilder chỉ tạo
được lệnh cập nhật cho lệnh truy vấn đầu tiên.
Ví dụ: cách thức CommandBuilder phát sinh lệnh cho các Command
Console.WriteLine(bo_phat_sinh.GetUpdateCommand.CommandText)
' kết quả in ra
' UPDATE VATTU SET mavtu = ? , tenvtu = ? , dvtinh = ? WHERE ( (mavtu = ?)
' AND ((? = 1 AND tenvtu IS NULL) OR (tenvtu = ?))
' AND ((? = 1 AND dvtinh IS NULL) OR (dvtinh = ?)) )
Console.WriteLine(bo_phat_sinh.GetDeleteCommand.CommandText)
' kết quả in ra
' DELETE FROM VATTU WHERE ( (mavtu = ?) AND (( ? = 1 AND tenvtu IS NULL)
' OR (tenvtu = ?)) AND (( ? = 1 AND dvtinh IS NULL) OR (dvtinh = ?)) )
Cú pháp:
Update(<mảng dòng>)
Phương thức này cập nhật các dòng <mảng dòng> vào nguồn dữ liệu
<mảng dòng>: Mảng các đối tượng lớp DataRow, thường mảng này là kết quả trả về của phương thức
GetChanges của DataSet
Update(<dataset>)
Phương thức này cập nhật các thay đổi trên tất cả các bảng của <dataset> vào nguồn dữ liệu
<dataset>: Đối tượng DataSet mà DataAdapter sẽ cập nhật vào nguồn
Update(<datatable>)
Phương thức này cập nhật các thay đổi trên DataTable vào nguồn dữ liệu
<datatable>: Đối tượng DataTable mà DataAdapter sẽ cập nhật vào nguồn
Phương thức này cập nhật các thay đổi trên bảng có tên <tên bảng> trong DataSet vào nguồn dữ liệu
Khi phương thức Update được gọi, DataAdapter sẽ kiểm tra tình trạng các dòng là thêm mới, sửa đổi,
xóa và gọi thực hiện tự động các Command tương ứng cho mỗi dòng. Nếu các Command chưa được
tạo sẽ phát sinh lỗi. Chúng ta có thể tạo và gán cho mỗi loại Command trên DataAdapter hoặc tự động
phát sinh thông qua CommandBuilder như đề cập ở mục trên.
Thông thường, mỗi Command trên DataAdapter có một tập hợp tham số kết hợp với nó. Các tham số
này được ánh xạ với dòng đang cập nhật thông qua thuộc tính:
SourceColumn: Cho biết tên cột trên dòng được cập nhật liên kết với tham số
SourceVersion: Cho biết giá trị của phiên bản nào trên dòng được cập nhật truyền vào vị trí
tham số.
Các giá trị của SourceVersion
Giá trị Mô tả
Current Tham số dùng giá trị hiện hành của cột. Đây là giá trị mặc định.
Default Tham số dùng giá trị mặc định đã qui định cho cột.
Original Tham số dùng giá trị gốc: giá trị từ khi bảng được lấy về từ nguồn dữ liệu
hay từ lần gọi cập nhật lần trước.
Proposed Tham số sử dụng một giá trị đề nghị.
Bài 6
DATASET, DATATABLE,
DATARELATION VÀ DATAVIEW
Tóm tắt
Lý thuyết 6 tiết - Thực hành 5 tiết
Kết thúc bài học này, học viên có thể 1. DataSet 3.3, 4.2, 4.3
làm việc với dữ liệu thông qua các đối 2. DataTable
tượng ADO.NET
3. DataRelation
4. DataView
I. DataSet
Một trong những điểm khác biệt chính giữa ADO và ADO.NET là đối tượng DataSet. Như đã trình bày ở
chương trước, DataSet là một mô hình CSDL quan hệ thu nhỏ đáp ứng nhu cầu của ứng dụng.
DataSet chứa các bảng (DataTable), các quan hệ (DataRelation). DataSet thuộc không gian tên sau:
SysTem.Data
New SysTem.Data.DataSet()
Hoặc
New SysTem.Data.DataSet(<tên>)
<Dataset>.Tables.Add()
Một bảng mới tự động tạo ra với tên mặc nhiên (Table1, Table2,…) và đưa vào tập hợp Tables của
DataSet
<Dataset>.Tables.Add(<tên bảng>)
Một bảng mới tự động tạo ra với tên là <tên bảng> và đưa vào tập hợp Tables
<Dataset>.Tables.Add(<bảng>)
Kinh nghiệm giảng dạy:
Tên bảng trong DataSet có phân biệt chữ HOA chữ thường. Nghĩa là có thể có 2 bảng
tên "table1" và "Table1"
Ví dụ:
Imports SysTem.Data
…
Dim dst As New DataSet("Ví dụ")
Dim bang As New DataTable("Bảng 1")
Dst.Tables.Add(bang)
<DataSet>.Tables.AddRange(<mảng DataTable>)
<mảng DataTable>: Là một mảng các DataTable đã tạo ra muốn đưa vào DataSet
Ví dụ:
Cú pháp:
Xóa <DataTable> khỏi tập hợp Tables của DataSet.
<DataSet>.Tables.Remove(<DataTable>)
Xóa <DataTable> có tên là <tên bảng> khỏi tập hợp Tables của DataSet.
<DataSet>.Tables.Remove(<tên bảng>)
Xóa <DataTable> có chỉ số là <chỉ số> khỏi tập hợp Tables của DataSet.
<DataSet>.Tables.RemoveAt(<chỉ số>)
Tuy nhiên, bảng có thể đang hiển thị dữ liệu trên Form nên chúng ta cần kiểm tra xem có thể xóa được
không với cú pháp:
<DataSet>.Tables.CanRemove(<DataTable>)
<DataSet>.Tables.Clear()
<DataSet>.Tables.Contains(<tên DataTable>)
Phương thức trả về True nếu trong Tables có DataTable có tên <tên DataTable>, ngược lại là False.
<DataSet>.Tables.IndexOf(<tên DataTable>)
<DataSet>.Tables.IndexOf(<DataTable>)
<DataSet>.Tables.Count
<DataSet>.HasChanges()
Phương thức kiểm tra sự thay đổi của tất cả các dòng dữ liệu trên các bảng (thêm mới, xóa bỏ, sửa
đổi) và trả về True nếu có, ngược lại False.
Phương thức kiểm tra sự thay đổi của tất cả các dòng dữ liệu trên các bảng có trạng thái như <trạng
thái dòng> và trả về True nếu có, ngược lại False..
<DataSet>.GetChanges()
Phương thức trả về bản sao của DataSet gồm những dòng dữ liệu đã bị thay đổi trên các bảng (do
thêm mới, xóa bỏ, sửa đổi).
Phương thức trả về bản sao của DataSet gồm những dòng dữ liệu đã bị thay đổi có trạng thái như
<trạng thái dòng>.
Ví dụ:
Dim ds As DataSet
If dst.HasChanges() then ds = dst.GetChanges()
…
If dst.HasChanges(DataRowState.Modified) then
ds = dst.GetChanges(DataRowState.Modified)
End If
<DataSet>.AcceptChanges()
Phương thức cập nhật các thay đổi kể từ lúc lấy dữ liệu về hoặc từ lần gọi AcceptChanges trước.
Trên DataTable, DataRow cũng có phương thức tương ứng. Khi gọi AcceptChanges của DataSet sẽ kéo
theo gọi AcceptChanges của DataTable, đến lượt kéo theo gọi AcceptChanges của DataRow.
<DataSet>.RejectChanges()
Phương thức này của DataSet phục hồi tất cả các thay đổi kể từ lúc lấy dữ liệu về hoặc từ lần gọi
AcceptChanges trước.
Khi gọi RejectChanges của DataSet sẽ kéo theo gọi RejectChanges của DataTable, DataRow.
Trong quá trình trộn lẫn dữ liệu, các ràng buộc được bỏ qua: thuộc tính EnforceConstraints có giá trị
False. Cuối quá trình, nếu ràng buộc nào không thể chuyển lại True sẽ làm phát sinh một Exception. Vì
vậy, chúng ta cần giải quyết các vi phạm ràng buộc trước khi gán EnforceConstraints với giá trị True.
Phương thức này có rất nhiều cách sử dụng.
Cú pháp:
<DataSet>.Merge(<mảng dòng>)
<DataSet>.Merge(<DataTable>)
<DataSet>.Merge(<DataSet>)
Trộn một Dataset bên ngoài và cấu trúc của nó vào DataSet.
<giữ thay đổi>: nếu là True, các thay đổi từ bên ngoài được giữ nguyên trên DataSet, là False không
thay đổi theo bên ngoài.
Trộn một Dataset bên ngoài và cấu trúc của nó vào DataSet.
<xử lý khi cấu trúc khác nhau>: tùy theo giá trị truyền vào.
Trộn một mảng dòng bên ngoài và cấu trúc của nó vào DataSet.
Trộn một DataTable bên ngoài và cấu trúc của nó vào DataSet.
Các giá trị của <xử lý khi cấu trúc khác nhau>
Tên Mô tả
Add Nếu khác nhau, thêm các cột mới vào cấu trúc của DataSet.
Error Nếu khác nhau phát sinh lỗi.
Ignore Nếu khác nhau, bỏ qua các cột mới.
<DataSet>.Dispose()
Khi được gọi, mọi tài nguyên trên vùng nhớ mà DataSet đang sử dụng sẽ được giải phóng.
Field hoặc các Field của bảng cha trong quan hệ phải thỏa yêu cầu tính duy nhất.
Chỉ có thể thiết lập quan hệ giữa hai bảng trong cùng DataSet
Chúng ta sử dụng phương thức Add của tập hợp Relations trong DataSet với các cú pháp sau.
Cú pháp:
<đối tượng DataRelation>: đối tượng này phải được tạo sẵn sẽ đề cập ở phần sau
<DataColumn trên bảng cha>, <DataColumn trên bảng con>: Các đối tượng này thuộc lớp
DataColumn sẽ đề cập ở phần sau là các cột tham gia quan hệ trên bảng cha và bảng con tương ứng
<mảng DataColumn trên bảng cha>, <mảng DataColumn trên bảng con>: Các mảng này là mảng các
cột tham gia quan hệ trên bảng cha và bảng con tương ứng.
Mặc định, khi tạo quan hệ giữa hai bảng, các ràng buộc đồng thời được tạo ra cho trên mỗi bảng như
sau:
Ràng buộc duy nhất trên bảng cha dựa vào các cột của bảng cha tham gia vào quan hệ (nếu
chưa có)
Ràng buộc khóa ngoại trên bảng con dựa vào các cột trên bảng cha và bảng con trong quan hệ.
Tham số <tạo ràng buộc> cho phép chúng ta quy định có tạo ràng buộc hay không: True có tạo, False
không tạo.
<mảng quan hệ>: là một mảng các quan hệ đã tạo ra muốn đưa vào DataSet.
Cú pháp:
<DataSet>.Relations.Remove(<quan hệ>)
Xóa quan hệ có tên là <tên quan hệ> khỏi tập hợp Relations.
<DataSet>.Relations.RemoveAt(<chỉ số>)
Tuy nhiên, quan hệ có thể đang được sử dụng nên chúng ta cần kiểm tra xem có thể xóa được không
với cú pháp:
<DataSet>.Relations.CanRemove(<quan hệ>)
<DataSet>.Relations.Clear()
Phương thức trả về True nếu trong Relations có quan hệ tên <tên quan hệ>, ngược lại là False
II. DataTable
Dữ liệu các bảng trong nguồn dữ liệu được lấy về và đưa vào các DataTable. DataTable thuộc không
gian tên System.Data.DataTable
Có các cách khai báo như sau:
Cú pháp:
New DataTable()
New DataTable(<tên bảng>)
II.2. DataColumn
Cấu trúc của bảng là tập hợp các DataColumn với các thuộc tính của chúng. Chúng ta có thể tạo cấu
trúc của bảng từ cấu trúc bảng trong nguồn dữ liệu hoặc tạo lập từ các DataColumn.
DataColumn thuộc không gian tên System.Data.DataColumn
New DataColumn()
New DataColumn(<tên cột>)
New DataColumn(<tên cột>,<kiểu dữ liệu>)
Kinh nghiệm giảng dạy:
Kiểu dữ liệu của DataColumn được khai báo thông qua cú pháp
System.Type.GetType("<kiểu dữ liệu>")
Chuỗi kiểu dữ liệu phải đúng như không gian tên, tên lớp có phân biệt chử Hoa chữ
thường
Các khai báo sau đây sẽ bị lỗi:
Dim cot As New DataColumn(“a”, System.Type.GetType(“System.string”))
Æ Phải là System.String
Dim cot As New DataColumn(“a”, System.Type.GetType(“String”))
Æ Phải là System.String
Dim cot As New DataColumn(“a”, System.Type.GetType(“System.Integer”))
Æ Không có System.Integer nhưng System.Int32
Ví dụ:
Bang_dien_vien.Columns.Add("Gioi_tinh",Type. _
GetType("System.String"), "IIF(Phai,'Nam','Nữ')")
Hiển thị dữ liệu của các bảng khác trong cùng Dataset thông qua quan hệ
Ví dụ: Tạo thêm cột Ten_VK trên Bang_xuat_dien
thông qua quan hệ VO_KICHXUAT_DIEN đã được
tạo và sơ đồ quan hệ các bảng như sau
Bang_xuat_dien.Columns.Add("Ten_VK",System.Type.GetType("System.String"),_
"Parent(VO_KICHXUAT_DIEN).Ten_VK")
Tên Mô tả
CONVERT Chuyển đổi biểu thức sang kiểu dữ liệu của .Net FrameWork theo cú pháp
CONVERT(<biểu thức>, <kiểu dữ liệu>)
<biểu thức>: biểu thức cần chuyển đổi
<kiểu dữ liệu>: kiểu dữ liệu muốn chuyển sang
LEN Lấy độ dài của chuỗi
LEN(<biểu thức>)
ISNULL Kiểm tra biểu thức có trả về trị Null, nếu có hàm trả về giá trị thay thế,
ngược lại trả về chính trị của biểu thức
ISNULL(<biểu thức>, <giá trị thay thế>)
<giá trị thay thế>: trị thay thế khi biểu thức là Null
IIF Sử dụng như hàm IIF của VB.NET
IIF(<biểu thức luận lý>, <giá trị khi biểu thức đúng>, _
<giá trị khi biểu thức sai>)
TRIM Cắt các ký tự trắng ở hai đầu biểu thức
TRIM(<biểu thức>)
SUBSTRING Lấy chuỗi con trong biểu thức
SUBSTRING(<biểu thức>, <vị trí bắt đầu>, <số ký tự>)
<vị trí bắt đầu>: vị trí bắt đầu chuỗi con trên biểu thức
<số ký tự>: số ký tự sẽ lấy cho chuỗi con trên biểu thức
II.3. DataRow
Dữ liệu lưu trữ trong DataTable qua các DataRow.
DataRow thuộc không gian tên System.Data.DataRow. Để tạo một DataRow chúng ta dùng phương
thức AddNew của DataTable. Sau đây là các thuộc tính và các phương thức của DataRow
cột truyền vào , giá trị trả về theo phiên bản truyền vào:
<datarow>.Item(<tên>,<phiên bản>)
<datarow>.Item(<cột>,<phiên bản>)
<datarow>.Item(<chỉ số>,<phiên bản>)
Phiên bản có các trị sau :
Current: Dòng chứa trị hiện hành.
Default: Dòng chứa phiên bản mặc định.
Đối với dòng có DataRowState là Added, Modified hoặc Current, phiên bản
mặc định là Current.
Đối với dòng có DataRowState là Deleted, phiên bản mặc định là phiên bản
Original.
Đối với dòng có DataRowState là Detached, phiên bản mặc định là phiên bản
Proposed.
Original: Dòng chứa trị gốc.
Proposed: Dòng chứa trị đã chỉnh sửa
ItemArray Tất cả nội dung của DataRow dưới dạng một mảng.
RowError Mô tả nội dung lỗi của dòng, nếu đang bị lỗi.
RowState Trả về tình trạng của DataRow và có các trị sau :
Added: Dòng đã được thêm vào tập hợp Rows nhưng chưa được cập nhật.
Deleted: Dòng đã được đánh dấu hủy bằng phương thức Delete.
Detached: Dòng không thuộc về tập hợp Rows gồm những dòng sau:
Dòng đã được tạo mới nhưng chưa đưa vào tập hợp Rows
Dòng đã bị loại bỏ khỏi tập hợp bằng phương thức Remove, RemoveAt của
bảng
Dòng đã bị đánh dấu hủy bằng Delete và sau đó đã gọi AcceptChanges của
Datarow.
Modified: Dòng đã được sửa đổi nhưng chưa được cập nhật.
Unchanged: Dòng không thay đổi kể từ lúc đọc từ nguồn dữ liệu hoặc từ lần
cập nhật trước.
Table Trả về tên bảng chứa DataRow.
GetParentRow Trả về dòng có quan hệ nhánh cha với đối tượng dòng đang tham chiếu theo
các cú pháp:
GetParentRow(<đối tượng DataRelation>)
GetParentRow(<tên DataRelation>)
GetParentRow(<đối tượng DataRelation>, <phiên bản>)
GetParentRow(<tên DataRelation>, <phiên bản>)
IsNull Cho biết trị của cột truyền vào có mang trị Null.
IsNull(<DataColumn>)
IsNull(<chỉ số của DataColumn>)
IsNull(<tên DataColumn >)
IsNull(<DataColumn>, <phiên bản>)
II.4. Constraint
Constraint (ràng buộc) là một quy tắc áp dụng cho một hoặc nhiều cột để bảo đảm tính toàn vẹn dữ
liệu trên DataTable.
Constraint thuộc không gian tên System.Data.Constraint
Có 2 loại Constraint:
System.Data.ForeignKeyConstraint: ràng buộc khóa ngoại
System.Data.UniqueConstraint: ràng buộc duy nhất
Những ràng buộc này do chúng ta tạo ra hoặc do thiết lập quan hệ giữa các bảng trong DataSet mà có.
Chúng ta có thể không cho phát sinh ràng buộc bằng tham số <tạo ràng buộc> = False khi thiết lập
quan hệ với phương thức <Dataset>.Relations.Add đã đề cập trong mục tạo quan hệ giữa hai
DataTable trong một Dataset.
Do có 2 loại ràng buộc nên chúng ta có các cú pháp tạo mới khác nhau cho mỗi loại.
II.4.1. ForeignKeyConstraint
Cú pháp:
Columns Trả về các cột tham gia khóa ngoại trên DataTable con
ConstraintName Tên của ràng buộc
DeleteRule Qui định cách xử lý khi một DataRow trên DataTable cha bị hủy, có các trị :
Cascade: Xóa các DataRow tương ứng trên DataTable con
None: Không làm gì cả.
SetDefault: Gán trị mặc định của DataColumn cho các dòng trên
DataTable con liên quan đến dòng vừa bị xóa trên bảng cha
SetNull: Gán trị DBNull cho các dòng trên DataTable con ứng với dòng
vừa bị xóa trên DataTable cha.
RelatedColumns Trả về các cột tham gia khóa ngoại trên DataTable cha.
RelatedTable Trả về DataTable cha.
Table Trả về DataTable con.
UpdateRule Qui định cách xử lý khi một dòng trên bảng cha thay đổi, có các trị:
Cascade: Cập nhật giá trị thay đổi trên DataTable cha vào các dòng
tương ứng trên DataTable con
None: Không làm gì cả.
SetDefault: Gán trị mặc định của cột cho các dòng trên DataTable con
ứng với dòng vừa thay đổi trên DataTable cha
SetNull: Gán trị DBNull cho các dòng trên DataTable con ứng với dòng
vừa thay đổi trên DataTable cha.
II.4.3. UniqueConstraint
Cú pháp:
<DataTable>.Columns.Count
<DataTable>.Columns.Add()
Tạo mới, đưa vào cấu trúc DataTable và trả về một DataColumn mới
<DataTable>.Columns.Add(<tên DataColumn>)
Tạo và đưa vào cấu trúc DataTable, một DataColumn mới tên là tham số truyền vào
<DataTable>.Columns.Add(<DataColumn>)
Tạo và đưa vào cấu trúc DataTable, một DataColumn mới tên là tham số truyền vào và có kiểu dữ liệu
là kiểu truyền vào
Tạo và đưa vào cấu trúc DataTable, một DataColumn mới tên là tham số truyền vào, có kiểu dữ liệu là
kiểu truyền vào và trị của DataColumn tính theo biểu thức truyền vào.
<DataTable>.Columns.AddRange(<mảng DataColumn>)
Đưa vào cấu trúc DataTable, mảng các DataColumn truyền vào.
II.5.5. Kiểm tra có thể loại bỏ DataColumn khỏi cấu trúc DataTable
Cú pháp:
<DataTable>.Columns.CanRemove(<DataColumn>)
Phương thức thực hiện một số kiểm tra như : DataColumn có thuộc về cấu trúc DataTable hay không,
có liên quan đến ràng buộc hoặc quan hệ của DataTable không và trả về kết quả True/False.
II.5.6. Kiểm tra cấu trúc DataTable có DataColumn tên truyền vào
<DataTable>.Columns.Contains(<tên DataColumn>)
Phương thức trả về True/False. Chúng ta dùng phương thức kiểm tra này trước khi thực hiện một
phương thức khác trên DataColumn
<DataTable>.Columns.Remove(<tên DataColumn>)
<DataTable>.Columns.RemoveAt(<chỉ số>)
<DataTable>.Columns.Clear()
<DataTable>.Rows.Count
Các cách sau áp dụng cho cả hai cách thông qua Item và không có Item
<DataTable>.Rows.Add(<DataRow>)
<DataTable>.Rows.Add(<mảng trị>)
Tạo một dòng mới với các trị trong mảng trị ứng với thứ tự các DataColumn và đưa vào tập hợp Rows
của DataTable.
<DataTable>.Rows.InsertAt(<DataRow>,<vị trí>)
<DataTable>.Rows.Remove(<DataRow>)
<DataTable>.Rows.RemoveAt(<chỉ số>)
<DataTable>.Rows.Clear()
II.6.7. Để kiểm tra trên khóa chính có chứa trị truyền vào
Cú pháp:
<DataTable>.Rows.Contains(<trị>)
Phương thức kiểm tra trên cột khóa chính xem có dòng nào chứa <trị> và trả về True nếu tìm thấy,
ngược lại trả về False
<DataTable>.Rows.Contains(<mảng trị>)
Phương thức kiểm tra trên các cột khóa chính có dòng nào chứa bộ giá trị <mảng trị> và trả về True
nếu tìm thấy, ngược lại trả về False. Thứ tự trị truyền vào phải theo thứ tự các cột khóa trên
DataTable.
<DataTable>.Rows.Find(<trị>)
Phương thức trả về dòng chứa <trị> trên cột khóa chính. Nếu không tìm thấy trả về Nothing
<DataTable>.Rows.Find(<mảng trị>)
Phương thức trả về DataRow chứa bộ giá trị <mảng trị> trên các cột khóa chính. Thứ tự trị truyền vào
phải theo thứ tự các cột khóa trên DataTable.
II.6.9. Minh họa tạo thao tác với tập hợp Rows
Ví dụ sau đây sẽ sử dụng cấu trúc của DataTable PHONGBAN, NHANVIEN phần trên và thêm vào các
mẩu tin.
Ví dụ:
' tạo ràng buộc duy nhất là khóa chính cho DataTable PHONGBAN
bang_phong.Constraints.Add("Khoa", bang_phong.Columns("Mapb"), True)
' tạo một ràng buộc duy nhất trên cột Manv của DataTable NHANVIEN
Dim khoa_duy_nhat As New UniqueConstraint( bang_nhan_vien.Columns("Manv"))
' tạo ràng buộc khóa ngoại trên cột Mapb của PHONGBAN và Mapb của NHANVIEN
Dim khoa_ngoai as New ForeignKeyConstraint(bang_phong.Columns(“Mapb”), _
bang_nhan_vien.Columns("Mapb"))
' Đưa hai ràng buộc vừa tạo vào tập hợp Constraints
bang_nhan_vien.Constraints.Add(khoa_duy_nhat)
bang_nhan_vien.Constraints.Add(khoa_ngoai)
<DataTable>.NewRow()
Phương thức này trả về một DataRow mới có cấu trúc như của DataTable với các giá trị mặc định
nhưng chưa đưa vào tập hợp Rows (nghĩa là chưa thuộc về DataTable, có trạng thái là Detached). Và
một khi được đưa vào tập hợp sẽ có trạng thái là Added.
<DataTable>.Clear()
II.8.3. Sao chép cấu trúc, ràng buộc của DataTable thành DataTable khác
Cú pháp:
<DataTable>.Clone()
Phương thức trả về một DataTable đã có sẵn cấu trúc và ràng buộc của DataTable nhưng không có dữ
liệu
II.8.4. Sao chép cấu trúc, ràng buộc và dữ liệu của DataTable thành DataTable khác
Cú pháp:
<DataTable>.Copy()
Phương thức trả về một DataTable đã có sẵn cấu trúc, ràng buộc và dữ liệu của DataTable. DataTable
trả về có cùng cấp với DataTable - nếu DataTable là đối tượng của một lớp kế thừa, DataTable trả về
cũng thuộc lớp đó.
II.8.5. Để lấy ra một bản sao những thay đổi trên DataTable
Cú pháp:
<DataTable>.GetChanges()
Phương thức trả về một DataTable gồm những dòng dữ liệu đã thay đổi kể từ lần lấy dữ liệu từ nguồn
về hoặc từ lần cập nhật trước vào DataTable bằng Phương thức AcceptChanges.
Như trên nhưng chỉ trả về những dòng có tình trạng đúng với <trạng thái DataRow>.
<DataTable>.GetErrors()
Phương thức trả về một mảng các DataRow bị lỗi. Phương thức này được gọi sau khi gọi GetChanges
nhằm phát hiện các dòng bị lỗi để xử lý.
<DataTable>.AcceptChanges()
Phương thức cập nhật các thay đổi kể từ lần cập nhật trước hoặc khi DataTable được mở vào chính nó.
Sau khi thực hiện tất cả các DataRow đều có trạng thái Unchanged. Những DataRow có trạng thái
Deleted bị loại bỏ khỏi DataTable.
<DataTable>.RejeptChanges()
Phương thức phục hồi lại các giá trị kể từ lần cập nhật trước hoặc khi DataTable được mở vào chính
DataTable. Sau khi thực hiện, tất cả các dòng mới thêm vào đều bị loại bỏ. Những DataRow có trạng
thái Deleted, Modified được phục hồi lại tình trạng gốc.
Phương thức thực hiện tính toán theo <biểu thức tính toán> trên những dòng thỏa điều kiện của <biểu
thức lọc> và trả về giá trị tính toán được kiểu Object.
Trong <biểu thức tính toán>, phải có hàm thống kê (Count, Sum,…)
<biểu thức lọc> : phải có dạng <tên cột> <toán tử> <giá trị>
Ví dụ: Dựa DataTable NHANVIEN ở trên, để đếm các nhân viên nữ thuộc phòng Hành chánh
<DataTable>.Select()
Phương thức trả về mảng các DataRow trên DataTable theo thứ tự của khóa chính nếu có.
Phương thức trả về mảng các DataRow trên DataTable thỏa điều kiện của <biểu thức lọc> theo thứ tự
của khóa chính nếu có.
Phương thức trả về mảng các DataRow trên DataTable thỏa điều kiện của <biểu thức lọc> theo thứ tự
của <biểu thức sắp xếp>.
Phương thức trả về mảng các DataRow trên DataTable thỏa điều kiện của <biểu thức lọc> theo thứ tự
của <biểu thức sắp xếp> và có RowState ứng với tham số <trạng thái dòng>.
Ví dụ: Dựa DataTable NHANVIEN ở trên, chọn ra các nhân viên thuộc phòng Hành chánh
Tên Mô tả
ColumnChanged Sự kiện xảy ra sau khi giá trị trên cột của một dòng đã thay đổi.
Tham số EventArgs chứa thông tin:
Column: DataColumn thay đổi
ProposedValue: giá trị thay đổi của DataColumn
ColumnChanging Sự kiện xảy ra khi giá trị trên cột của một DataRow đang thay đổi. Tham số
EventArgs chứa thông tin như ColumnChanged
RowChanged Sự kiện xảy ra sau khi một DataRow đã thay đổi thành công (không phát
sinh Exception)
Tham số EventArgs chứa thông tin:
Action: hành động đã xảy ra trên dòng
Row: dòng có hành động xảy ra
RowChanging Sự kiện xảy ra khi một dòng đang thay đổi. Tham số EventArgs chứa thông
tin như RowChanged
RowDeleted Sự kiện xảy ra sau khi một dòng trên DataTable đã bị đánh dấu hủy. Tham
số EventArgs chứa thông tin như RowChanged
RowDeleting Sự kiện xảy ra trước khi một dòng trên DataTable bị đánh dấu hủy. Tham số
EventArgs chứa thông tin như RowChanged
III. DataRelation
DataSet quản lý quan hệ giữa các DataTable trong DataSet qua tập hợp Relations. Đây là những đối
tượng DataRelation chứa thông tin về mối quan hệ đã tạo ra trong DataSet.
Quan hệ giữa hai DataTable nói lên sự liên quan của một dòng (DataRow) trên DataTable cha với các
DataRow trên DataTable con. Do đó, chúng ta có thể thấy được mối quan hệ đó qua việc hiển thị dữ
liệu các dòng tương ứng trên DataTable con (một cách tự động qua việc liên kết lưới DataTable con với
quan hệ đã tạo) khi dòng hiện hành trên DataTable cha thay đổi.
Ràng buộc, ngược lại, nhằm bảo vệ tính toàn vẹn dữ liệu thông qua mối quan hệ sẽ kiểm tra sự tồn tại
của DataRow bên DataTable cha khi thêm, sửa trên DataTable con hoặc kiểm tra tồn tại các dòng con
khi hủy trên DataTable cha
DataRelation thuộc tên lớp System.Data.DataRelation
Cú pháp:
<tạo ràng buộc>: Có giá trị True/False cho biết khi thiết lập quan hệ sẽ tạo luôn các ràng buộc hay
Kinh nghiệm giảng dạy:
Chỉ có thể thiết lập quan hệ giữa hai DataTable chỉ khi hai DataTable đó thuộc về một
DataSet
Hoặc:
dst.Relations.Add("PB_NV", bang_phong.Columns("Mapb"), _
bang_nhan_vien.Columns(“Mapb”))
Hoặc:
bang_phong.ChildRelations.Add("PB_NV", bang_phong.Columns("Mapb"), _
bang_nhan_vien.Columns(“Mapb”))
Hoặc:
bang_nhan_vien.ParentRelations.Add("PB_NV", bang_phong.Columns("Mapb"), _
bang_nhan_vien.Columns(“Mapb”))
IV. DataView
Trong các đối tượng chúng ta đã tìm hiểu, vẫn còn thiếu một số chức năng như tìm kiếm với ý nghĩa
định vị trí, sắp xếp, lọc dữ liệu…ADO.Net đưa ra DataView như một đối tượng thuận tiện cho việc liên
kết dữ liệu với các điều khiển, sắp xếp…nhằm bổ sung cho những yêu cầu trên và cung cấp cho chúng
ta một cách hiển thị dữ liệu tùy biến của DataTable.
Với chức năng hiển thị dữ liệu tùy biến, DataView cho phép hiển thị dữ liệu của một DataTable qua các
điều khiển khác nhau với các số liệu khác nhau như dùng một điều khiển hiển thị tất cả các dòng dữ
liệu trên DataTable và một điều khiển khác hiển thị dữ liệu của những dòng đã bị đánh dấu hủy cũng
của DataTable đó …
Mặc định mỗi DataTable có sẵn một DataView thông qua thuộc tính DefaultView.
DataView thuộc tên lớp System.Data.DataView
New DataView()
New DataView(<DataTable>)
Tạo một DataView mới từ <DataTable> gồm những dòng thoả điều kiện <biểu thức lọc> và có tình
trạng như <trạng thái dòng>, được hiển thị theo cách sắp xếp <biểu thức sắp xếp>
trị sau:
Added: Dòng mới thêm vào chưa cập nhật.
CurrentRows: Dòng hiện hành bao gồm những dòng không thay đổi,
dòng mới và dòng đã thay đổi.
Deleted: Dòng đánh dấu hủy.
ModifiedCurrent: Dòng đã được thay đổi và giá trị hiển thị là phiên
bản hiện hành, tức phiên bản đã sửa đổi từ dữ liệu gốc.
ModifiedOriginal: Dòng đã được thay đổi và giá trị hiển thị là phiên
bản gốc.
None: Không gì cả.
OriginalRows: Dòng gốc bao gồm các dòng không thay đổi và dòng
đã đánh dấu hủy.
Unchanged: Dòng không thay đổi.
Sort Tên cột hoặc các cột của DataTable dùng sắp xếp dữ liệu trên Dataview ngăn
cách nhau bằng dấu phẩy (đọc ghi). Nếu sắp xếp tăng không ghi thêm gì
hoặc "ASC", sắp xếp giảm thêm "DESC"
Table DataTable (đọc ghi) mà DataView đang lấy dữ liệu
<DataView>.Add()
Phương thức trả về một DataRowView (sẽ đề cập đến phần sau).
<DataView>.Delete(<chỉ số>)
Phương thức thực hiện đánh dấu hủy dòng trên DataView có chỉ số truyền vào. Sau khi thực hiện, dòng
có trạng thái là Deleted và có thể phục hồi bằng RejectChanges.
<DataView>.Find(<giá trị>)
Phương thức thực hiện tìm kiếm <giá trị> trên DataView và trả về chỉ số của dòng đầu tiên thỏa giá trị
tìm. DataView phải được sắp xếp trên cột muốn tìm kiếm.
Phương thức thực hiện tìm kiếm <mảng giá trị> trên các cột tương ứng của DataView và trả về chỉ số
của dòng đầu tiên thỏa giá trị tìm. DataView phải được sắp xếp trên các cột có trị muốn tìm kiếm.
Nếu tìm thấy, phương thức trả về chỉ số dòng tìm thấy, ngược lại không tìm thấy trả về -1
<DataView>.FindRows(<giá trị>)
Phương thức thực hiện tìm kiếm <giá trị> trên DataView và trả về những dòng thỏa giá trị tìm.
DatView phải được sắp xếp trên cột muốn tìm kiếm.
<DataView>.FindRows(<mảng giá trị>)
Phương thức thực hiện tìm kiếm <mảng giá trị> trên các cột tương ứng của DataView và trả về những
dòng thỏa giá trị tìm. DataView phải được sắp xếp trên các cột có trị muốn tìm kiếm.
Nếu tìm thấy, phương thức trả về mảng các dòng thỏa điều kiện, ngược lại trả về mảng không có phần
tử nào
Ví dụ : Để tìm kiếm nhân viên có họ “Lê Công”, tên “Minh” trên bang_nhan_vien đề cập ở trên
IV.4. DataRowView
Tương tự DataRow trên DataTable, DataRowView là một cách hiển thị của DataRow theo phiên bản
(xin xem phần dưới) trên DataView.
Khi liên kết với một điều khiển dữ liệu, chỉ có một phiên bản của DataRowView được hiển thị. Các phiên
bản đó là Default, Original, Current, và Proposed như của DataRow.
Chỉ có thể tạo DataRowView bằng phương thức AddNew của DataView
Delete Đánh dấu hủy bỏ dòng. Dòng chưa thực sự bị hủy cho đến khi phương thức
AcceptChanges của bảng được gọi.
EndEdit Chấm dứt giai đoạn chỉnh sửa và cập nhật các thay đổi trên dòng.
Bài 7
XÂY DỰNG CÁC LỚP XỬ LÝ
Tóm tắt
Lý thuyết 3 tiết - Thực hành 10 tiết
Kết thúc bài học này, học viên có thể 1. Mô hình đa tầng 5.3, 5.4, 5.5
xây dựng các lớp xử lý sử dụng trong 2. Xây dựng lớp xử lý lưu trữ
mô hình lập trình dữ liệu
3. Xây dựng lớp xử lý nghiệp vụ
Người
Xử lý thể hiện
Xử lý nghiệp vụ
Xử lý lưu trữ
Dữ liệu
Trong mô hình này, ứng dụng được phân chia thành nhiều tầng với các chức năng khác nhau:
Tầng xử lý thể hiện có chức năng hiển thị thông tin ra màn hình giao tiếp và tiếp nhận thông tin từ
người dùng
Tầng xử lý nghiệp vụ cung cấp và xử lý thông tin của dữ liệu từ hai tầng kế cận (thể hiện và lưu
trữ)
Tầng xử lý lưu trữ có chức năng truy xuất và cập nhật thông tin vào nguồn dữ liệu (đọc/ghi)
Vì tính độc lập của các tầng, mô hình này thích hợp cho việc xây dựng ứng dụng khi thay đổi nguồn dữ
liệu, môi trường lập trình, … và tận dụng được khả năng tái sử dụng.
Có nhiều hình thức xây dựng lớp cho mỗi tầng, nhưng trong phạm vi giáo trình này, chúng tôi sẽ sử
dụng nguyên tắc kế thừa nhằm thuận lợi cho học viên trong khi triển khai
Imports System.Data
Imports System.Data.OleDb
Module PHAN_MEM
Public Const Chuoi_lien_ket As String = _
"Provider=Microsoft.JET.OLEDB.4.0;"
End Module
' Thuộc tính cho phép đọc và ghi nội dung truy vấn dữ liệu cần thực hiện
cho thể hiện
Public Property Chuoi_SQL() As String
Get
Return mChuoi_SQL
End Get
Set(ByVal Value As String)
mChuoi_SQL = Value
End Set
End Property
' Thuộc tính cho phép truy xuất và gán tên bảng muốn truy vấn dữ liệu
Public Property Ten_bang() As String
Get
Return mTen_bang
End Get
Set(ByVal Value As String)
mTen_bang = Value
End Set
End Property
' Thuộc tính chứa đối tượng kết nối đến nguồn dữ liệu
Public Shared Property Ket_noi() As OleDbConnection
Get
Return mKet_noi
End Get
Set(ByVal Value As OleDbConnection)
mKet_noi = Value
End Set
End Property
' Thuộc tính chỉ đọc cho biết số dòng trên DefaultView của DataTable
Public ReadOnly Property So_dong() As Long
Get
Return Me.DefaultView.Count
End Get
End Property
#End Region
' Thủ tục khởi tạo đọc bảng theo nội dung yêu cầu
Public Sub New(ByVal pTen_bang As String, ByVal pChuoi_SQL As String)
MyBase.New(pTen_bang)
mTen_bang = pTen_bang
mChuoi_SQL = pChuoi_SQL
Doc_bang()
End Sub
#End Region
#Region " Khai báo phương thức xử lý – cung cấp thông tin "
' Thủ tục khởi tạo đối tượng đọc ghi dữ liệu và khai báo thông tin cho đối
tượpng kết nối
' Thực hiện lấy cấu trúc và dữ liệu vào DataTable. Sau cùng phát sinh các
lệnh cập nhật
Private Sub Doc_bang()
If mChuoi_SQL = "" Then mChuoi_SQL = "SELECT * FROM " & mTen_bang
If mKet_noi Is Nothing Then
mKet_noi = New OleDbConnection
mKet_noi.ConnectionString = Chuoi_lien_ket & "Data Source=" &
Chuoi_CSDL
End If
Try
mBo_doc_ghi = New OleDbDataAdapter(mChuoi_SQL, mKet_noi)
mBo_doc_ghi.Fill(Me)
mBo_doc_ghi.FillSchema(Me, SchemaType.Mapped)
mBo_doc_ghi.SelectCommand.CommandText = "Select * FROM " &
mTen_bang
Dim Bo_phat_sinh As New OleDbCommandBuilder(mBo_doc_ghi)
Catch ex As OleDbException
End Try
End Sub
' Hàm cập nhật các thay đổi trên DataTable vào CSDL và cập nhật các dòng
trên DataTable
' về trạng thái không thay đổi. Nếu cập nhật được, hàm trả về True; ngược
lại, bỏ qua các
' thay đổi và trả về False
Public Function Ghi() As Boolean
Dim ketqua As Boolean = True
Try
mBo_doc_ghi.Update(Me)
Me.AcceptChanges()
Catch e As Exception
Me.RejectChanges()
ketqua = False
End Try
Return ketqua
End Function
' Thủ tục lọc dữ liệu của DefaultView theo điều kiện lọc truyền vào
Public Sub Loc_du_lieu(ByVal pDieu_kien As String)
Try
Me.DefaultView.RowFilter = pDieu_kien
Catch ex As Exception
End Try
End Sub
#End Region
#Region " Khai báo các phương thức thực hiện lệnh "
' Hàm thực hiện nội dung lệnh truyền vào và trả về số mẩu tin được cập
nhật, nếu thành
' công. Nếu không thành công, hàm trả về -1
Public Function Thuc_hien_lenh(ByVal Lenh As String) As Integer
Try
Dim Cau_lenh As New OleDbCommand(Lenh, mKet_noi)
mKet_noi.Open()
Dim ket_qua As Integer = Cau_lenh.ExecuteNonQuery()
mKet_noi.Close()
Return ket_qua
Catch ex As OleDbException
Return -1
End Try
End Function
' Hàm thực hiện nội dung lệnh tính toán thống kê truyền vào và trả về kết
quả, nếu thành
' công. Nếu không thành công, hàm trả về Nothing
Public Function Thuc_hien_lenh_tinh_toan(ByVal Lenh As String) As Object
Try
Dim Cau_lenh As New OleDbCommand(Lenh, mKet_noi)
mKet_noi.Open()
Dim ket_qua As Object = Cau_lenh.ExecuteScalar
mKet_noi.Close()
Return ket_qua
Catch ex As OleDbException
Return Nothing
End Try
End Function
#End Region
Imports System.Data
Imports System.Data.OleDb
Public Class XL_DIEN_VIEN
Inherits XL_BANG
#Region " Khai báo phương thức khởi tạo "
' Khởi tạo toàn bộ danh sách diễn viên
Public Sub New()
MyBase.New("DIEN_VIEN", "Select * From DIEN_VIEN")
End Sub
' Khởi tạo thông tin diễn viên theo khóa chính
Public Sub New(ByVal pMDV As Int32)
MyBase.New("DIEN_VIEN", "Select * From DIEN_VIEN Where MDV = " & pMDV)
End Sub
' Khởi tạo danh sách diễn viên theo điều kiện
Public Sub New(ByVal pChuoi_SQL As String)
MyBase.New("DIEN_VIEN", pChuoi_SQL)
End Sub
#End Region
…
End Class
#Region " Khai báo phương thức xử lý tìm kiếm thông tin "
Public Sub Tim(ByVal pDong_dieu_kien As DataRow)
Dim chuoi_Dk As String = ""
Dim mang_Dk As New ArrayList
Dim so_Pt As Byte = 0
If Not IsDBNull(pDong_dieu_kien("Ho_ten_dv")) Then
mang_Dk.Add("Ho_ten_dv LIKE '" & _
pDong_dieu_kien("Ho_ten_dv") & "*'")
End If
Bài 8
THIẾT KẾ CÁC MÀN HÌNH
Tóm tắt
Lý thuyết 6 tiết - Thực hành 15 tiết
Bài học này giúp cho học viên thiết 4. Các điều khiển hiển thị dữ liệu 5.6, 5.7, 5.8, 5.9,
kế và cài đặt các dạng màn hình cơ 5. Màn hình đơn 5.10, 5.11, 5.12,
bản trong ứng dụng Visual Basic 5.14
6. Màn hình một nhiều
7. Màn hình lọc theo điều kiện Bài làm thêm: 5.13
Các sự kiện
Tên Mô tả
SelectedIndexChanged Xảy ra khi thuộc tính SelectedIndex thay đổi (do lệnh và tương tác).
SelectedValueChanged Xảy ra khi thuộc tính SelectedValue thay đổi (do lệnh và tương tác).
SelectionChangeCommitted Xảy ra khi dòng chọn thay đổi và đã được cập nhật (do tương tác)
I.3. DataGrid
DataGrid là điều khiển cho phép liên kết dữ liệu dạng bảng gồm các dòng và các cột. Đặc điểm của
DataGrid trong .NET là có thể liên kết với DataSet chứa nhiều bảng, quan hệ và có thể hiện thị từng bảng
dữ liệu theo từng quan hệ trên lưới. Lưới lúc này hiển thị như cây thư mục, chọn bảng nào lưới sẽ chuyển
sang liên kết dữ liệu của bảng đó và xuất hiện các nút di chuyển về bảng trước, v.v…
SetDataBinding Liên kết dữ liệu với lưới thông qua DataSource và DataMember.
SetDataBinding(<datasource>, <datamember>)
New DataGridTableStyle()
Các thuộc tính của DataGridTableStyle đều kế thừa của DataGrid nên bảng dưới chỉ trình bày các thuộc
tính mới và đáng chú ý:
I.4.2. TableStyles
Do lưới có thể dùng hiển thị dữ liệu của các nguồn khác nhau nên chúng ta có thể tạo nhiều
DataGridTableStyle cho phù hợp với mỗi nguồn dữ liệu. Các DataGridTableStyle của lưới được tập hợp
lại thành TableStyles. Là một tập hợp (collection) nên TableStyles có các thuộc tính và phương thức
đặc trưng của tập hợp như Count, Item, Add, AddRange, Clear, Contains, Remove, RemoveAt. Cách sử
dụng các thuộc tính và phương thức của TableStyles cũng giống như cách đã trình bày trước đây về
các tập hợp khác.
New DataGridBoolColumn()
New DataGridTextBoxColumn()
Ngoài các thuộc tính chung nói trên, mỗi loại còn có các thuộc tính riêng của nó
I.5.2. GridColumnStyles
GridColumnStyles là tập hợp các DataGridColumnStyle (cả DataGridBoolColumn lẫn
DataGridTextBoxColumn) của một DataGridTableStyle.
Ví dụ:
Kinh nghiệm giảng dạy:
Luôn luôn tạo các DataGridColumnStyle và thêm chúng vào GridColumnStyles của
DataGridTableStyle trước khi thêm DataGridTableStyle này vào TableStyles của lưới.
Khi thêm một DataGridTableStyle rỗng (chưa có các DataGridColumnStyle) vào
TableStyles, các DataGridColumnStyle sẽ được phát sinh tự động, vì thế khi chúng ta
thêm DataGridColumnStyle vào sẽ phát sinh lỗi do có các DataGridColumnStyle có
MappingName trùng nhau
I.7.2. BindingManagerBase
BindingManagerBase là đối tượng quản lý và cho phép đồng bộ dữ liệu các điều khiển trên màn hình
cùng liên kết đến cùng một đối tượng nguồn. Đây là một lớp trừu tượng. BindingManagerBase thuộc
không gian tên System.Windows.Forms.BindingManagerBase gồm hai lớp:
System.Windows.Forms.CurrencyManager
System.Windows.Forms.PropertyManager
CurrencyManager thực hiện việc đồng bộ bằng cách duy trì một con trỏ đến dòng hiện hành trên danh
sách. Các điều khiển liên kết đến dòng hiện hành sẽ hiển thị thông tin của cùng một dòng.
PropertyManager được dùng để duy trì thuộc tính hiện hành của đối tượng, đúng hơn là thuộc tính của
đối tượng hiện hành trên danh sách.
Cách tạo thường dùng nhất là từ đối tượng BindingContext của Form như sau:
Cú pháp: Khởi tạo một DataGridColumnStyle
Dim bm As BindingManagerBase = _
<form>.BindingContext(<nguồn dữ liệu>)
Hoặc:
Dim bm As BindingManagerBase = _
<form>.BindingContext(<nguồn dữ liệu>, <thành phần>)
Nếu nguồn dữ liệu là đối tượng chỉ trả về một thuộc tính, BindingContext sẽ trả về một
ProtertyManager. Ví dụ liên kết Text của Label với Text của Textbox.
Nếu nguồn dữ liệu là đối tượng chứa một danh sách, BindingContext sẽ trả về một CurrencyManager.
Ví dụ nguồn là DataSet, DataTable, DataView... một CurrencyManager được trả về.
I.7.3. BindingContext
Phát sinh từ lớp đối tượng System.Windows.Forms.BindingContext, BindingContext là đối tượng quản lý
các BindingManagerBase. Các đối tượng kế thừa từ lớp Control đều có thể có BindingContext. Tuy
nhiên, chỉ có Form và các điều khiển chứa các điều khiển khác như Groupbox, TabControl, Panel mới có
thể tạo một BindingContext để quản lý các BindingManagerBase hiển thị dữ liệu của các điều khiển
chứa trong nó.
Tuy cùng liên kết với một nguồn dữ liệu (cách tham chiếu hoàn toàn giống nhau), nhưng hai
BindingContext sẽ phát sinh hai BindingManagerBase khác nhau và không đồng bộ dữ liệu với nhau.
I.7.4. Các thủ tục nhập xuất dữ liệu trên màn hình
Để hiển thị dữ liệu trên màn hình, chúng ta sử dụng các điều khiển đã đề cập ở trên thông qua thuộc
tính liên kết dữ liệu và thường có các thủ tục nhập xuất sau:
Thủ tục Xuat_ho_so_<ten_bang>: xuất các trị của dòng đang làm việc ra các điều khiển trên
màn hình
Thủ tục Xuat_ho_so_<ten_bang>_moi: xuất các trị mặc định ra các điều khiển trên màn hình
để chuẩn bị tiếp nhận thông tin của dòng mới
Thủ tục Nhap_ho_so_<ten_bang>: nhập trị của các điều khiển trên màn hình vào các cột tương
ứng trên dòng đang làm việc.
Thủ tục Xuat_danh_sach_chon_<ten_bang>: sử dụng khi cấp nguồn liệt kê cho các điều khiển
ComboBox, ListBox, ListCheckBox
Thủ tục Xuat_luoi_<ten_bang>: sử dụng khi xuất dữ liệu của bảng ra lưới (DataGrid)
<bang_du_lieu> là biến tham chiếu đến đối tượng của lớp xử lý nghiệp vụ trên màn hình.
Them_moi là biến theo dõi trạng thái thêm mới của dòng đang làm việc trên màn hình.
Danh_sach là biến tham chiếu đến BindingManagerBase của <bang_du_lieu> đang hiển thị trên
màn hình
Xuat_ho_so_<ten_bang>_moi:
Private Sub Xuat_ho_so_<ten_bang>_moi()
Them_moi = True
<Điều khiển 1>.<Thuộc tính liên kết dữ liệu> = _
<Giá trị mặc định của cột hoặc của kiểu>
<Điều khiển 2>.<Thuộc tính liên kết dữ liệu> = _
<Giá trị mặc định của cột hoặc của kiểu>
. . .
End Sub
Nhap_ho_so_<ten_bang>:
Private Sub Nhap_ho_so_<ten_bang>()
Danh_sach.Current(<Cột 1>) = <Điều khiển 1>.<Thuộc tính liên kết dữ
liệu>
Danh_sach.Current(<Cột 2>) = <Điều khiển 2>.<Thuộc tính liên kết dữ
liệu>
. . .
End Sub
Nếu trên màn hình có sử dụng các điều khiển liệt kê (ListControl) như ComboBox, ListBox,
CheckListBox, lúc này cần phải có thêm nguồn dữ liệu liệt kê cho điều khiển (<bang_liet_ke>) và có
thêm thủ tục:
Xuat_danh_sach_chon_<ten_bang>:
‘ <bang_liet_ke> là đối tượng cung cấp danh sách liệt kê cho điều khiển
Private Sub Xuat_danh_sach_chon_<ten_bang>()
<Điều khiển liệt kê>.DisplayMember = _
<Tên cột muốn hiển thị trên bảng liệt kê>
<Điều khiển liệt kê>.ValueMember = _
<Tên cột muốn liên kết trên bảng dữ liệu>
<Điều khiển liệt kê>.DataSource = <bang_liet_ke>
End Sub
Nếu màn hình hiển thị dữ liệu dưới dạng dòng cột sử dụng DataGrid, thủ tục xuất lưới sẽ là:
Xuat_luoi_<ten_bang>:
Private Sub Xuat_luoi_<ten_bang>()
<Điều khiển lưới>.DataSource = <bang_du_lieu>
End Sub
Ketqua = <điều kiện kiểm tra khác trên cùng điều khiển nếu có>
If Not Ketqua Then
' Thông báo lỗi
<Điều khiển>.Focus
End If]
End If
Return Ketqua
End Function
Kiem_tra_ghi_<ten_bang > As Boolean: phối hợp các hàm kiểm tra trên để lấy kết quả tổng
hợp
Private Function Kiem_tra_ghi_<ten_bang> As Boolean
Dim Ketqua As Boolean = Kiem_tra_<ten_cot_1> AndAlso _
Kiem_tra_<ten_cot_2> ...
Return Ketqua
End Function
Kiem_tra_huy_<ten_bang > As Boolean: kiểm tra hủy dữ liệu có vi phạm ràng buộc toàn vẹn
không (kiểm tra trên các bảng nhiều)
Private Function Kiem_tra_huy_<ten_bang> As Boolean
Dim Ketqua As Boolean
Dim bang As _
New XL_<TEN_BANG_CON>(<điều kiện lọc theo khóa bảng kiểm tra>)
Ketqua = (bang.So_dong = 0)
' kiểm tra trên các bảng con khác nếu cần
Return Ketqua
End Function
Sự kiện nhấn của các nút lệnh di chuyển: thay đổi dòng hiện hành nếu hợp lệ
Private Sub Dau_Click(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Dau.Click
If Danh_sach.Position > 0 Then
Danh_sach.Position = 0
End If
End Sub
Sự kiện nhấn của nút thêm: Thực hiện xuất hồ sơ mới và đưa con trỏ nhập liệu về điều khiển
bắt đầu
Private Sub Them_Click(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Them.Click
Xuat_ho_so_<ten bang>_moi()
<Điều khiển bắt đầu>.Focus
End Sub
Sự kiện nhấn của nút ghi: Thực hiện kiểm tra ghi. Nếu hợp lệ, thực hiện các bước:
+ Nếu Them_moi là True (đang thêm), thêm dòng mới trên Danh_sach
+ Nhập hồ sơ
+ Thực hiện ghi dữ liệu của lớp xử lý
+ Xuất hồ sơ
Private Sub Ghi_Click(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Ghi.Click
If Kiem_tra_ghi_<ten bang>() Then
If Them_moi Then Danh_sach.AddNew()
Nhap_ho_so_<ten bang>()
Danh_sach.EndCurrentEdit()
<bang_du_lieu>.Ghi()
Xuat_ho_so_<ten bang>()
End If
End Sub
Sự kiện nhấn của nút không: Thực hiện xuất lại thông tin trước đó.
Private Sub Khong_Click(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Khong.Click
Xuat_ho_so_<ten bang>()
End Sub
Sự kiện nhấn của nút hủy: Nếu Them_moi là True, thực hiện xuất hồ sơ; ngược lại nếu kiểm tra
hủy hợp lệ và đồng ý xóa thực hiện:
+ Đánh dấu hủy dòng hiện hành trên Danh_sach
+ Thực hiện ghi dữ liệu của lớp xử lý
+ Xuất hồ sơ
Private Sub Huy_Click(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Huy.Click
If Them_moi Then
Xuat_ho_so_<ten bang>()
Exit Sub
Else If Kiem_tra_huy_<ten bang>() Then
If MsgBox("Đồng ý hủy ?", MsgBoxStyle.Question + _
MsgBoxStyle.YesNo,"Xin cho biết") = MsgBoxResult.Yes Then
Danh_sach.Current.Delete()
<bang_du_lieu>.Ghi()
End If
Else
' Thông báo lỗi
End If
End Sub
Sự kiện CurrentChanged của Danh_sach: Thực hiện xuất hồ sơ, nếu không phải đang thêm mới
Private Sub Danh_sach_CurrentChanged(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles Danh_sach.CurrentChanged
Được đọc theo trị cột khóa bảng phía một khi bảng phía một thay đổi dòng làm việc và xuất ra
lưới
Hoặc được lọc theo trị cột khóa bảng phía một khi bảng phía một thay đổi dòng làm việc và
xuất ra lưới (nếu đã được đọc toàn bộ từ đầu)
Ví dụ: Xử lý bảng nhiều được đọc theo khóa bảng một (khi số liệu bảng nhiều quá lớn)
Ví dụ: Xử lý bảng nhiều được đọc hết và được lọc theo khóa bảng một khi dòng hiện hành bảng một
thay đổi (khi số liệu bảng nhiều không lớn)
Trên đây là một dạng khác của màn hình lọc theo một điều kiện: (các bảng vở kịch, diễn viên, tham gia
được đọc khi mở màn hình)
Diễn viên được phân vai hiển thị dữ liệu THAM_GIA lọc theo vở kịch được chọn
Danh sách diễn viên hiển thị dữ liệu DIEN_VIEN đã loại trừ các diễn viên được phân vai
Ví dụ: bang_tham_gia và bang_dien_vien được khởi tạo khi mở màn hình
End Function
Các nút >, >> thực hiện thêm các dòng chọn trên Danh sách diễn viên vào bang_tham_gia và
lọc lại dữ liệu trên bang_dien_vien
Các nút <, << thực hiện hủy các dòng chọn trên Diễn viên được phân vai khỏi bang_tham_gia
và lọc lại dữ liệu trên bang_dien_vien
Khai báo một ComboBox mới và đưa vào tập hợp Controls của lớp và diều khiển này sẽ ẩn hiện
theo TextBox của cột và sẽ di chuyển đến vùng hiện hành của lưới.
DisplayMember, ValueMember và DataSource của ComboBox sẽ được gán thông qua một
phương thức.
Để cập nhật dữ liệu cho lưới, chúng ta gán SelectedValue của ComboBox sau khi chọn thông
qua phương thức SetColumnAtRowValue
Xin xem thêm giáo trình.
VI.3. Tạo lớp DataGridColumnStyle cho phép định dạng chi tiết
Với lớp DataGridTextBoxColumn, chúng ta không thể định dạng riêng cho một ô. Vì vậy, cần xây dựng
một lớp có thể cho phép định dạng riêng biệt qua việc tạo một kiểu DataGridColumnStyle mới kế thừa
từ DataGridTextBoxColumn (xem thêm trong giáo trình)
Ví dụ:
Bài 9
BÁO BIỂU CRYSTAL REPORT
Tóm tắt
Lý thuyết 6 tiết - Thực hành 10 tiết
Bài học này giúp cho học viên cách 1. Giới thiệu CrysTal Reportl 5.15, 5.16, 5.18,
thiết kế báo biểu theo mô hình Pul, 2. Tạo báo biểu mô hình Pull, Push 5.19
Push trong VB.Net.
Bài làm thêm: 5.17
Xét về mặt thiết kế báo biểu, Crystal Report cung cấp đầy đủ các chức năng đinh dạng dữ liệu và các
chức năng phân nhóm, tính toán, sub – report và kể cả khả năng lập trình bằng formula dựa trên các
fomula field. Người dùng ngoài việc sử dụng formula field còn có thể tự xây dựng bộ thư viện hàm của
riêng mình và đưa vào Crystal Report thông qua các DLL. Bên cạnh khả năng thiết kế báo biểu thông
thường, Crystal Report còn cung cấp chức năng thiết kế biểu đồ dựa trên nguồn dữ liệu lấy từ CSDL.
Xét về mặt sử dụng báo biểu, công cụ hiển thị của Crystal Report cho phép người dùng tương tác rất
linh hoạt. Báo biểu hiển thị có thể được lọc lại các dữ liệu cần thiết hay xem một phần báo biểu bằng
cách sử dụng cấu trúc hiển thị dữ liệu dạng cây. Các Section trong báo biểu cũng có thể mở rộng hay
thu hẹp để hiển thị hay che bớt những dữ liệu không cần thiết. Một khi báo biểu đã được xây dựng,
người dùng còn có thể Export sang các dạng file khác như Word, Excel, HTML,…
Bằng cách tích hợp Crystal Report 8.5, Visual Studio .NET đem lại cho người dùng một công cụ xây
dựng báo biểu hiệu quả, tiết kiệm nhiều thời gian so với việc phải sử dụng các đối tượng in ấn để tự
phát sinh báo biểu. Chúng ta có thể sử dụng Report Expert để tạo ra báo biểu dựa vào wizard và
template định sẵn hay thiết kế chi tiết báo biểu bằng tay. Nội dung phần này không đề cập đến các chi
tiết thiết kế cụ thể (có thể tham khảo cách tạo báo biểu trên Crystal Report trong giáo trình Visual
Basic tập hai) nhưng tập trung vào việc tạo mới báo biểu trong Visual Studio .Net, hiển thị báo biểu
trong ứng dụng và sử dụng DataSet làm nguồn dữ liệu cho báo biểu.
Báo biểu là một phần của project do đó, để tạo mới một báo biểu chúng ta thực hiện thông qua menu
Project | Add new item… và lần lượt thực hiện
Trong phần Templates, chọn mục Crystal Report để tạo mới một báo biểu.
Trong phần Name của hộp thoại Add New Item nhập vào tên file báo biểu cần tạo.
Khi nhấn nút Open, Visual Studio .Net tự động chuyển đổi sang giao diện của Crystal Report để
chúng ta thực hiện việc tạo mới báo biểu. Có thể chọn tạo mới báo biểu ở một trong hai hình thức:
Wizard (Using Report Expert) hay tự thiết kế từ đầu (Blank Report). Chúng ta cũng có thể mở một
báo biểu đã tạo sẵn để đưa vào project.
Khi chọn Blank Report, khác với sử dụng phần mềm Crystal Report độc lập, Visual Studio .NET sẽ
chuyển ngay sang màn hình thiết kế mà không chọn CSDL cho báo biểu (xem hình trên)
Để chọn CSDL cho báo biểu, nhắp chuột phải trên mục Database Fields và chọn mục Add/Remove
Database
Một điểm cần chú ý khác trong quá trình thiết kế báo biểu đó là một số thay đổi trong giao diện so
với phần mềm Crystal Report chạy độc lập. Ví dụ, chúng ta sẽ tìm thấy TextObject trong phần
Toolbox hay thuộc tính của các đối tượng thiết kế có thể thay đổi trực tiếp từ cửa sổ Properties như
khi đang thiết kế form
Cuối cùng, cũng giống như Crystal Report Designer trên Visual Basic 6.0, chúng ta không thể
chuyển sang chế độ Preview để xem kết quả thiết kế báo biểu, thay vào đó cần phải sử dụng đối
tượng Crystal Report Viewer của Visual Studio .NET.
Màn hình dưới là thiết kế của báo biểu hiển thị danh sách các mặt hàng theo từng loại, lấy nguồn dữ
liệu từ CSDL Northwind của SQL Server.
Mô hình Pull
Trong mô hình này, trình sẽ kết nối với nguồn dữ liệu và lấy về dữ liệu yêu cầu. Kết nối với nguồn và
lệnh SQL truy xuất dữ liệu đều do Crystal Reports xử lý; chúng ta không phải viết dòng lệnh nào. Nếu
không có dòng lệnh nào viết cho lúc thực hiện, báo biểu sử dụng mô hình Pull.
Mô hình Push
' Gán report sẽ hiển thị trên cv là một thể hiện của CrystalRport1
cv.ReportSource = New CrystalReport1
f.ShowDialog()
Khi thực hiện chương trình với đoạn lệnh trên, chúng ta sẽ có một màn hình hiển thị report tương tự
như hình dưới.
CrystalReportViewer có khá đầy đủ các chức năng, từ lật trang, in ấn, gửi mail, phóng lớn/thu nhỏ cho
tới tìm kiếm, định vị các group,…
Ví dụ:
Sau đây minh họa cách thiết kế báo biểu sử dụng DataSet làm nguồn dữ liệu.
Trong Project, tạo một DataSet mới
+ Menu Project | Add new item, chọn mục DataSet, trong phần Name, gõ vào tên của DataSet
là: Products_Schema.xsd
+ Thiết kế DataSet như sau:
+ Lưu DataSet lại sau khi tạo xong cấu trúc bảng
Tạo mới một báo biểu, khi chọn nguồn dữ liệu cho báo biểu chúng ta chọn mục ADO.NET
DataSet
+ Chọn DataSet vừa tạo
+ Chọn 2 bảng Categories và Products làm nguồn dữ liệu
+ Chọn OK để lưu lại nguồn dữ liệu của báo biểu
Khi chạy chương trình, báo cáo sẽ được hiển thị như sau:
Trên hình, dữ liệu đã được lọc lại so với báo cáo trước để chỉ hiển thị những Category có CategoryID
>4.
Báo biểu có thành phần Database cho biết nguồn dữ liệu hiển thị. Khi vị trí nguồn thay đổi, chúng ta
phải định lại vị trí nguồn mới cho báo biểu thông qua thông tin đăng nhập của Table, thuộc tập hợp
Tables của Database.
Thông tin đăng nhập thuộc lớp TableLogOnInfo trong không gian tên
CrystalDecisions.Shared.TableLogOnInfo với các thông tin:
Tên Mô tả
ConnectionInfo Đối tượng chứa thông tin kết nối của bảng.
DatabaseName Tên tập tin CSDL.
Password Mật khẩu truy cập nguồn CSDL
ServerName Tên server hoặc nguồn dữ liệu ODBC.
UserID Tên người dùng để truy cập CSDL.
Thông tin TableLogOnInfo của bảng có tính chỉ đọc và mặc định lưu giữ thông tin kết nối lúc chúng ta
khai báo nguồn để thiết kế báo biểu. Khi thay đổi và muốn cập nhật lại, chúng ta phải sử dụng phương
thức ApplyLogOnInfo của đối tượng Table với tham số là TableLogOnInfo chúng ta đã thay đổi.
Ví dụ: Minh họa khi nguồn dữ liệu là MS Access
rpt.Database.Tables(0).ApplyLogOnInfo(logOnInfo)
cv.ReportSource = rpt
f.ShowDialog()
<CrystalReport>.RecordSelectionFormula = _
"{<Tên bảng>.<Tên field>} <Toán tử so sánh> <Giá trị>"
<Toán tử so sánh> có thể là =, >=, <=, >, <, <>, In (<danh sách>), Not In (<danh sách>), In <giá
trị đầu> To <giá trị cuối>
<Giá trị> cần phải có ký hiệu của kiểu dữ liệu như ['] cho kiểu String, [#] cho kiểu DateTime
Hoặc sử dụng thuộc tính SelectionFormula của điều khiển hiển thị báo biểu CrystalReportViewer
Cú pháp:
<CrystalReportViewer>.SelectionFormula = _
"{<Tên bảng>.<Tên field>} <Toán tử so sánh> <Giá trị>"
<Tên tham số> là tên của tham số (ParameterField) đã tạo trong báo biểu.
<Giá trị> không cần có ký hiệu của kiểu dữ liệu.
Các gía trị thuộc tính của CrystalDecisions.[Shared].ExportFormatType (loại tập tin)
Giá trị Mô tả
Excel Xuất ra tập tin .XLS.
HTML40 Xuất ra tập tin HTML4.0
NoFormat Xuất ra tập tin không kiểu.
PortableDocFormat Xuất ra tập tin .PDF.
RichText xuất ra tập tin .RTF
WordForWindows xuất ra tập tin .DOC
Lớp xử lý Ý nghĩa
XL_BANG.vb Lớp đối tượng đọc ghi dữ liệu và một số chức năng khác
XL_<Nghiệp vụ>.vb Các lớp xử lý nghiệp vụ kế thừa từ lớp bảng ứng với mỗi bảng trong CSDL
5. MH_TRA_CUU.vb
6. BC_QUA_TRINH.rpt
Báo biểu đã được thiết kế để hiển thị thông tin như hình:
Câu 1. Biến khai báo trong VB.NET thuộc loại nào dưới đây:
a) Value Type, Pointer Type
b) Value Type, Reference Type
c) Pointer Type, Reference Type
d) Pointer Type, Reference Type, Value Type
Câu 2. Giả sử khai báo biến d có kiểu ngày:
Dim d As Date
d = Now
Hãy cho biết câu lệnh nào sau đây sẽ in ra ngày hiện hành theo dạng ngày tháng năm:
a) Msgbox (d.Date)
b) MsgBox (d.ToString(“dd/mm/yyyy”))
c) MsgBox (d.ToString(“dd/MM/yyyy”))
d) MsgBox (d.ToShortDateString())
Câu 3. Chọn lý do khai báo thủ tục sau đây bị lỗi:
Private Sub TEST(ByVal a As Integer, ByVal b As Integer, Optional ByVal c As Boolean )
' các lệnh
End Sub
a) Lỗi vì thiếu kiểu dữ liệu của thủ tục
b) Lỗi vì từ khóa ByVal của các tham số
c) Lỗi vì tham số Optional không có giá trị mặc định
d) Lỗi vì thừa từ ByVal trong Optional ByVal.
Câu 4. Tính chất nào sau đây không thuộc các tính chất của Lập trình hướng đối tượng:
a) Tính Cụ thể (Concret) c) Tính Bảo bọc (Encapsulation)
b) Tính Đa hình (Polymorphism) d) Tính Kế thừa (Inheritance)
Câu 5. Có các dòng lệnh sau:
Public … Property <Ten thuoc tinh>
Get
' Trả về giá trị
End Get
End Property
Chọn từ khóa thích hợp để điền vào phần … của thuộc tính:
a) MustOverride c) WriteOnly
b) ReadOnly d) ReadWrite
Câu 6. Từ khóa Shared trong khai báo các thành phần cho biết thành phần đó:
a) Được sử dụng chung giữa các đối tượng thuộc lớp đó
b) Có thể sử dụng thành phần Shared thông qua tên lớp
c) Có thể sử dụng thành phần Shared thông qua một biến thuộc lớp đó, ngay cả khi chưa cấp phát vùng
nhớ cho biến.
d) Từ khóa Shared hàm ý tất cả các câu trên.
Câu 7. Các thành phần được khai báo với từ khóa Protected cho phép truy xuất:
a) Chỉ trong chính lớp nơi thành phần đó được khai báo
b) Trong chính lớp nơi thành phần đó được khai báo và trong các lớp kế thừa từ lớp đó
c) Chỉ trong chính lớp nơi thành phần đó được khai báo và trong các thể hiện của lớp đó.
d) Chỉ trong chính lớp nơi thành phần đó được khai báo và trong lớp cha của lớp đó.
Câu 8. Để tạo ra một đối tượng OleDbDataReader, chúng ta sử dụng cách nào sau đây:
a) Dim bo_doc As New System.OleDb.OleDbDataReader
b) ' với Lenh là đối tượng OleDbCommand đã tạo sẵn
Dim bo_doc As System.OleDb.OleDbDataReader = Lenh.ExecuteReader()
c) ' với Lenh là đối tượng OleDbCommand đã tạo sẵn
Dim bo_doc As System.OleDb.OleDbDataReader = Lenh.ExecuteDataReader()
d) Các câu a, b đúng
Câu 9. Cho bảng dữ liệu như sau:
CONG_VIEC
MCV Ten_cong_viec Don_vi_tinh Don_gia
1 Đào móng đất cấp 3 M3 20000
2 Đổ bê tông 4x6 M3 22000
3 Đổ bê tông 1x2 M3 35000
4 Xây tường 10 M2 10000
5 Xây tường 20 M3 25000
6 Đổ đất nền M3 10000
7 Đóng cốp pha M2 25000
8 Lót gạch men M2 30000
Cho biết biến ketqua chứa giá trị nào khi thực hiện đoạn lệnh sau đây. Biết rằng Ket_noi là đối tượng
OleDbConnection đã kết đến nguồn dữ liệu cần thiết:
Dim Lenh As New System.OleDb.OleDbCommand("Select Ten_cong_viec From CONG_VIEC", _
Ket_noi)
Ket_noi.Open
Dim ketqua = Lenh.ExecuteScalar()
Ket_noi.Close
a) "Đào móng đất cấp 3" c) "Đào móng đất cấp 3, Đổ bê tông 4x6,
b) "Lót gạch men" …, Lót gạch men"
d) Chương trình bị lỗi
Câu 10. Đối tượng OleDbCommandBuilder được dùng để ?
a) Khai báo các OleDbCommand
b) Phát sinh ra OleDbDataAdapter
c) Phát sinh ra SelectCommand của OleDbDataAdapter
d) Phát sinh ra các DeleteCommand, InsertCommand và UpdateCommand của OleDbDataAdapter dựa
trên SelectCommand của nó
Câu 11. Cho bảng NHAN_VIEN có cấu trúc sau:
Field Name Field Type Field Size Description
MNV Autonumber Long Integer Mã nhân viên
Ho_ten Text 50 Họ tên nhân viên
Gioi_tinh Yes/No Giới tính: Yes: Nam ; No: Nữ
Ngay_sinh Date/Time Ngày sinh
Dia_chi Text 50 Địa chỉ
Với Mo_ket_noi là hàm trả về OleDbConnection kết nối đến CSDL chứa bảng NHAN_VIEN nói trên
Xét các câu lệnh sau:
(1) Dim bo_doc_ghi As New OleDbDataAdapter("Select Ho_ten, Gioi_tinh, Ngay_sinh, Dia_chi " _
& "From NHAN_VIEN", Mo_ket_noi)
(2) Dim bo_phat_sinh As New OleDbCommandBuilder(bo_doc_ghi)
Khi thực hiện, bo_phat_sinh sẽ không phát sinh được các lệnh DeleteCommand, InsertCommand và
UpdateCommand vì:
a) Dòng lệnh khai báo (2) thiếu tham số
b) OleDbCommandBuilder không phải là đối tượng phát sinh các Command còn lại
c) Nội dung SelectCommand của OleDbDataAdapter không có cột khóa chính hoặc cột duy nhất
d) Nội dung SelectCommand của OleDbDataAdapter không phải từ hai bảng trở lên
c) bang_hoa_don.Columns.Add("So_mat_hang", Type.GetType(System.Integer), _
"Count(Child.MHD)")
d) bang_hoa_don.Columns.Add("So_mat_hang", Type.GetType("System.Integer"), _
"Count(Child(HD_CT).MHD)")
Câu 17. Thuộc tính RowState của DataRow có các giá trị nào sau đây:
a) Added, Deleted, Detached, Modified, Unchanged
b) Added, Deleted, Modified, Unchanged
c) Added, Deleted, Modified Original, Modified Current, Unchanged
d) Deleted, EditAdd, EditInProgress, Unchanged
Câu 18. Khai báo nào sau đây không hợp lệ trên phần General:
a) Const Chuoi_vi_tri = "\..\Du_lieu\CSDL.mdb"
b) Const Chuoi_vi_tri As String= "\..\Du_lieu\CSDL.mdb"
c) Const Chuoi_vi_tri As String= Application.StartUpPath & "\..\Du_lieu\CSDL.mdb"
d) Private Chuoi_vi_tri As String= Application.StartUpPath & "\..\Du_lieu\CSDL.mdb"
Câu 19. Date.Today trả về giá trị của ngày hiện hành. Trên một máy tính có Region Settings qui định cách hiển
thị ngày tháng năm là dd/MM/yyyy, trên Immediate Window, kết quả nào sau đây được in ra khi thực
hiện dòng lệnh :
?Date.Today (giả sử có trị ngày 15 tháng 6 năm 2005)
a) #15/06/2005# c) #6/15/2005#
b) #15/06/2005 12:00:00# d) #06/15/2005#
Câu 20. Phương thức AddNew của DataView trả về một DataRowView và khi được gọi số dòng trên DataView
(<Dataview>.Count) tăng thêm một. Trên DataTable mà DataView được tạo, số dòng
(<DataTable>.Rows.Count) sẽ:
a) Bằng số dòng trên DataView
b) Bằng số dòng trên DataView có tình trạng là DataViewRowState.CurrentRows
c) Không thay đổi so với số dòng trên DataTable trước khi AddNew của DataView được gọi
d) Các câu trên đều sai
Câu 21. Xét đoạn lệnh sau trên DataTable bang_nv:
Dim a,b As Integer
a = bang_nv.Rows.Count
bang_nv.Rows(0).Delete()
b = bang_nv.Rows.Count
Hãy cho biết a và b thế nào sau khi thực hiện thành công đoạn lệnh trên (không bị lỗi)
a) a<b
b) a=b
c) a>b
d) a=b+1
Câu 22. Để xuất dữ liệu liệt kê ra điều khiển ComboBox, khi sử dụng đoạn lệnh sau:
<ComboBox>.DisplayMember = "<tên cột hiển thị>"
<ComboBox>.ValueMember = "<tên cột lưu trữ>"
<ComboBox>.DataSource = <DataTable>
Người ta thấy các dòng trên ComboBox hiển thị cùng nội dung là "System.Data.DataRowView"
Hãy chọn giải thích đúng cho trường hợp này
a) <tên cột hiển thị> không có trên <DataTable>
b) <tên cột lưu trữ> không có trên <DataTable>
c) <ComboBox>.DataSource phải sửa lại là <ComboBox>.RowSource
d) Các giải thích trên đều sai
Câu 23. Để gọi thực hiện báo biều Crystal Report BC_NHAN_VIEN, sử dụng đoạn lệnh nào sau đây:
a) Dim bb As New BC_NHAN_VIEN
bb.Show
I. Tạo CSDL
a) Mô tả
Vào mỗi cuối tháng, công ty xây dựng ABC dựa trên bảng chấm công và lương của các tổ xây dựng để
tính lương cho thợ. Mỗi tổ trưởng, ngoài phần lương của mình còn nhận được khoản phụ cấp trách nhiểm
trích từ lợi nhuận của công ty.
b) Cấu trúc các bảng
Tập tin cơ sở dữ liệu QL_LUONG.mdb gồm các bảng : (các field in đậm và gạch dưới là khóa chính)
Khi người dùng chọn các mục trong menu, thực hiện các yêu cầu tương ứng sau:
o Giới thiệu: dùng MsgBox hiển thị thông tin của thí sinh: Họ tên – Năm sinh
o Chọn thời gian: Hiển thị màn hình chọn thời gian câu 2 ở chế độ hộp thoại.
o Đóng: Hiển thị cửa sổ thông báo “Ứng dụng sẽ đóng lại. Bạn có đồng ý không ?”. Tùy theo trả lời của
người dùng, sẽ thực hiện đóng ứng dụng hay không (Có thể sử dụng hàm MsgBox).
o Tính lương: Hiển thị màn hình câu 3
Khi mở màn hình này mặc nhiên mở luôn màn hình chọn thời gian câu 2 ở chế độ hộp thoại
o Tiêu đề hiển thị "Tính lương tháng" <tháng làm việc> " năm " <năm làm việc>
o Điều khiển Tổ liệt kê các tổ xây dựng.
o Khi chọn một tổ xây dựng, Tổng lương hiển thị lương của tổ trong năm tháng làm việc, thực hiện các
yêu cầu sau:
o Nếu lương tổ > 0, lưới hiển thị thông tin tính lương của các thợ trong tổ được chọn ứng với năm tháng
làm việc nếu có. Nếu trong CSDL chưa có, cần phát sinh thông tin cho tổ được chọn ứng với năm
tháng làm việc.
o Nếu không tồn tại lương tổ được chọn, lưới sẽ không hiển thị.
o Cập nhật công cho phép cập nhật số công của thợ ứng với năm tháng làm việc:
Số công = số ngày trong tháng năm tính lương - số ngày nghỉ trong tháng
o Chia lương: thực hiện các bước:
o Xác định đơn vị lương của tổ được chọn = Tổng lương / Tổng(số công *HSL) của các thợ trong tổ
o Cập nhật cột Tien_luong = đơn vị lương * Số công * HSL cho các thợ trong tổ . Nếu là tổ trưởng, cập
nhật thêm cột Phu_cap = Tien_luong*0.05
o In phiếu lương: xuất báo biểu phiếu lương các thợ trong tổ được chọn ứng với năm tháng làm việc