Thứ Năm, 1 tháng 11, 2012

Các thuộc tính của RecordSET - ADO căn bản


RECORDSET - BỘ MẪU TIN

Recordset còn được gọi là bộ mẫu tin. Đây là đối tượng chính của mô hình ADo, đối tượng được dùng để hiển thị và cập nhật dữ liệu trong lập trình ứng dụng CSDL.

Mỗi dòng dữ liệu có trong bộ mẫu tin được gọi là mẫu tin (record). Tuy bộ mẫu tin có thể chứa nhiều mẫu tin nhưng tại một thời điểm, chúng ta chỉ có thể làm việc với đúng một mẫu tin gọi là mẫu tin hiện hành của bộ mẫu tin mà thôi. Mỗi cột dữ liệu có trong bộ mẫu tin được gọi là trường dữ liệu hay Field.

Phân lọai

Trong quá trình lập trình cơ sở dữ liệu, mỗi khi tạo ra bộ mẫu tin, chúng ta cần xác định trước lọai của bộ mẫu tin cần tạo. Có bốn lọai chính là: Static, Dynamic, Keyset và Forwardonly. Mỗi lọai trên đây sẽ được dùng tùy theo vị trí và ý nghĩa sử dụng như sau:

adOpenStatic: bộ mẫu tin sẽ được tạo tại máy con, mọi thay đổi trên dữ liệu nguồn của Recordset do những người dùng khác thực hiện sẽ không tự động cập nhật.

adOpenDynamic: bộ mẫu tin sẽ được tạo tại máy chủ và mọi thay đổi trên dữ liệu nguồn của Recordset sẽ tự động cập nhật hiển thị cho tất cả những người dùng đang làm việc trên cùng bộ mẫu tin. • adOpenKeyset: tương tự như lọai Dynamic, nhưng không tự cập nhật các mẫu tin bị xóa hay thêm mới bởi các người dùng đang sử dụng chung Recordset, không truy cập được những mẫu tin bị xóa do người dùng khác và các thay đổi do người dùng khác vẫn được hiển thị.

adOpenForwardOnly: bộ mẫu tin được tạo với lọai này sẽ nằm tại máy con như adOpenStatic và chỉ cho phép di chuyển mẫu tin đi tời bằng phương thức MoveNext.

Khai báo và khởi tạo bộ mẫu tin

1. Recordset với ADO Data Control

Trong quá trình làm việc với điều khiển ADO Data Control trước đây, chúng ta đã từng làm việc với bộ mẫu tin trong điều khiển ADO Data Control thông qua cú pháp:

<ado data control>.Recordset


Hoặc khai báo biến kiểu ADODB.Recordset, sau đó gán biến Recordset này với bộ mẫu tin có trong điều khiển ADO Data Control

Dim rst As New ADODB.Recordset
Set rst=<ado data control>.Recordset 


2. Tạo Recordset bằng lệnh

Làm việc với bộ mẫu tin trong điều khiển ADO Data Control có rất nhiều hạn chế, trong đó nổi bật nhất là phải đặt điều khiển ADo trên các form và các bộ mẫu tin phải được tạo trước tại thời điểm thiết kế. Môi trường lập trình chuyên nghiệp đòi hỏi mỗi người chúng ta phải có thể tạo và xử lý các đối tượng trong mô hình ADO, đặc biệt là đối tượng Recordset, tại thời điểm chạy chương trình.

Phần nội dung trình bày dưới đây sẽ trình bày cách khai báo và khởi tạo đối tượng Recordset tại thời điểm chạy chương trình.

Để làm việc với đối tượng bộ mẫu tin Recordset, chúng ta cần thực hiện các bước sau: Bước 1: Khai báo biến bộ mẫu tin

Dim rst As ADODB.Recordset 
Bước 2: Cấp phát vùng nhớ trước khi làm việc với rst

Set rst=New ADODB.Recordset 
Bước 3: Khởi tạo các giá trị cho biến bộ mẫu tin rst

Sử dụng phương thức Open theo cú pháp dưới đây để khởi tạo cho biến Recordset, rst như sau:
rst.Open [Source], [Connection], [Type], [Lock], [Option]


Trong đó:

Source: chuỗi xác định nguồn dữ liệu của bộ mẫu tin là tên một bảng hay chuỗi câu lệnh SQL.
Connection: mối kết nối dữ liệu sẽ được dùng.

Type: các hằng số chỉ ra lọai của Recordset. Thông thường, khi viết các ứng dụng chạy trên máy đơn, chúng ta thường dùng lọai adOpenStatic.

Lock: thuộc tính xác định trạng thái cho phép khóa dữ liệu khi cập nhật trên bộ mẫu tin. Các hằng trị của thuộc tính Lock gồm:

Trị hằng Ý nghĩa
adLockBatchOptimistic |4 |Với kiểu khóa này có thể cập nhật nhiều mẫu tin cùng lúc và các mẫu tin được cập nhật chỉ bị khóa khi phát lệnh cập nhật.

adLockOptimistic |3 |Cập nhật từng mẫu tin và mẫu tin được cập nhật chỉ bị khóa khi phát lệnh cập nhật.

adLockPessimistic |2 |Với kiểu này, mẫu tin sẽ bị khóa ngay từ khi chuyển sang trạng thái sửa đổi hay thêm mới. Chỉ có thể sử dụng kiểu khóa này với thuộc tính CursorLocation của recordset là adUseServer

adLockReadOnly |1 |Chỉ cho phép đọc

Việc quy định thuộc tính Lock của các Recordset cũng rất quan trọng. Nếu chúng ta cần tạo ra một bộ mẫu tin chỉ để tính tóan, thì có thể dùng adLockReadOnly. Trong khi đó, nếu muốn tạo một bộ mẫu tin để hiển thị và cập nhật dữ liệu, chúng ta nên dùng giá trị adLockOptimisticadLockBatchOptimistic hay adLockPessimistic.

Option: là thuộc tính xác định kiểu nguồn dữ liệu Source, có thể có các trị sau: Hằng trị |Ý nghĩa |Trị adCmdTable |Khi Source là tên bảng, tên bảng Query trên Access |2 adCmdText |Khi Source là truy vấn SQL |1 adCmdStoreProc|Khi Source là Stored Procedure trong SQL SERVER |4 Trong một số trường hợp, chúng ta có thể ghép bước 1 và bước 2 thành một bước duy nhất bằng cách vừa khai báo vừa cấp phát vùng nhớ bằng cú pháp như sau:

Dim rst As New ADODB.Recordset 


Các xử lý với bộ mẫu tin

Thuộc tính State

Tương tự như thuộc tính State đã trình bày trong phần Connection, thuộc tính State của bộ mẫu tin Recordset sẽ chỉ ra trạng thái của bộ mẫu tin là đang mở hay đóng. Thuộc tính này có các hằng trị sau:

adStateClosed (0) trạng thái đóng

adStateOpen (1) trạng thái mở

Đóng và mở bộ mẫu tin

Để đóng liên kết dữ liệu giữa một đối tượng Recordset với dữ liệu thật có trong cơ sở dữ liệu, chúng ta có thể dùng phương thức Close theo cú pháp

Rst.Close 
Sau đó, khi cần, chúng ta sẽ có thể tạo lại liên kết như dòng lệnh dưới đây:

If rst.State=adStateClosed then rst.Open
Truy xuất các trường dữ liệu

Khi cần truy xuất giá trị của một trường nào đó của Recordset, chúng ta có thể dùng một trong các cách sau:

<tên recordset>("<tên trường>").Value 
hoặc

<tên recordset>!<tên trường>.Value 
hoặc

<tên recordset>(index).Value 
Với Index là số thứ tự trường muốn truy xuất. Giá trị của Index được tính từ 0 đến số trường -1. Các thuộc tính mẫu tin thường dùng

• Thuộc tính Recordcount (trị Long, chỉ đọc): thuộc tính này chứa số mẫu tin hiện có trong bộ mẫu tin. Thuộc tính này thường chỉ được cập nhật khi có sự di chuyển mẫu tin hiện hành. Recordcount sẽ có trị là -1 khi không xác định được số mẫu tin hay khi kiểu con trỏ là adOpenForwardOnly.

• Thuộc tính BOF và EOF

_Thuộc tính BOF: nếu thuộc tính này có giá trị là True thì mẫu tin hiện hành đang đứng trước mẫu tin đầu tiên trong bộ mẫu tin Recordset. Lúc này, mọi thao tác như di chuyển mẫu tin về trước, xóa mẫu tin hiện hành, truy xuất giá trị các field...đều tạo ra lỗi. Ở các vị trí khác, thuộc tính BOF có giá trị là False.

_Thuộc tính EOF: tương tự như thuộc tính BOF, thuộc tính EOF sẽ chỉ ra mẫu tin hiện hành có đang đứng sau mẫu tin cuối cùng hay không. Nếu đúng, EOF có trị là True, ngược lại sẽ có trị là False. Cũng như BOF, nếu EOF là True, mọi thao tác như di chuyển mẫu tin về sau, xóa mẫu tin hiện hành, truy xuất giá trị các field...đều tạo lỗi.

AbsolutePostion (trị Long): thuộc tính chứa số thứ tự của mẫu tin hiện hành trong bộ mẫu tin Recordset, có các hằng đặc biệt sau:

_adPosUnknown: (-1) Recordset rỗng, vị trí hiện hành không xác định.

_adPosBOF: (-2) vị trí mẫu tin hiện hành ở BOF, nghĩa là thuộc tính BOF là True.

_adPosEOF: (-3) vị trí mẫu tin hiện hành ở EOF, nghĩa là thuộc tính EOF là True.

BookMark: (Trị Variant) thuộc tính lưu trữ thông tin vị trí của mẫu tin hiện hành trên Recordset. Chúng ta thường dùng thuộc tính này để lưu trữ và phục hồi vị trí mẫu tin hiện hành của bộ mẫu tin trong các xử lý cập nhật dữ liệu. Mỗi mẫu tin có trị Bookmark khác nhau.
Chú ý:

Sự khác biệt giữa AbsolutePosition và BookMark: tuy cùng xác định vị trí của mẫu tin hiện hành, nhưng sau khi huỷ một mẫu tin nằm trước vị trí hiện hành, giá trị AbsolutePosition sẽ bị thay đổi còn BookMark thì không.

EditMode: (chỉ đọc) chỉ tình trạng của mẫu tin hiện hành, có các trị sau:

Hằng Trị Ý nghĩa
adEditNone 0 Tình trạng bình thường
adEditInProgress 1 Tình trạng đang sửa đổi chưa cập nhật
adEditAdd 2 Tình trạng đang thêm mới chưa cập nhật
adEditDelete 4 Tình trạng được đánh dấu hủy chưa cập nhật
Kiểm tra Recordset rỗng

Thông thường các xử lý trên bộ mẫu tin Recordset chỉ có tác dụng khi bộ mẫu tin đó đang chứa số liệu. Có những xử lý như xóa, sửa, lọc dữ liệu...sẽ không họat động được khi bộ mẫu tin đang rỗng. Chính vì lý do này, trong một số xử lý, chúng ta sẽ kiểm tra nếu bộ mẫu tin Recordset sẽ xử lý theo một cách nào đó dựa vào cú pháp sau:

If rst.BOF and rst.EOF then 
    <xử lý khi recordset rst rỗng>
Else 
    <xử lý khi recordset rst có dữ liệu>
End If 
Hoặc

If rst.BOF and rst.EOF Then 
    <xử lý khi recordset rỗng>
    <thóat khỏi thủ tục, hàm>   
End If 
<>    <xử lý khi recordset rst có dữ liệu


Duyệt các mẫu tin của một Recordset

Để duyệt qua các mẫu tin của một Recordset, chúng ta có thể dùng một trong hai cấu trúc lệnh sau đây:
rst.MoveFirst 
Do While Not rst.EOF 
   <các xử lý trên mẫu tin hiện hành>
   rst.MoveNext 
Loop 


Hay là
For i=1 to rst.RecordCount 
   rst.AbsolutePostion=i 
   <các xử lý trên mẫu tin hiện hành> 
Next 


Thêm một mẫu tin

Cú pháp được dùng là:

<Tên recordset>.AddNew 


Đọan chương trình dưới đây sẽ minh họa cách thêm một mẫu tin vào Recordset

On Error Goto Err_Msg 
rst.AddNew 
Exit Sub 
Err_Msg: 
Msgbox "Lỗi thêm dữ liệu" 


Xóa mẫu tin 

Cú pháp để xóa mẫu tin trong một Recordset là:

<Tên recordset>.Delete
'Xóa mẫu tin hiện hành 


Tuy nhiên cần lưu ý là sau khi xóa mẫu tin thì mẫu tin hiện hành sẽ không có giá trị. Vì vậy, sau khi xóa, chúng ta cần di chuyển mẫu tin hiện hành sang mẫu tin sau để cập nhật lại mẫu tin hiện hành của Recordset. Đọan chương trình dưới đây sẽ minh họa xử lý xóa mẫu tin hiện hành của một Recordset.

Private Sub cmdDelete_Click()'Xử lý nút xóa
On Error Goto Err_Msg 
rst.Delete
rst.MoveNext
If rst.EOF And Not rst.BOF Then
 rst.MoveLast
End If 
Exit Sub 
Err_Msg: 
Msgbox "Lỗi xóa mẫu tin" 
End Sub


Cập nhật dữ liệu

Để ghi lại những thay đổi của mẫu tin hiện hành trong một Recordset chúng ta dùng lệnh theo cú pháp như sau:

<tên recordset.Update

Ngược lại, nếu không muốn lưu các thay đổi chúng ta thực hiện lệnh

<tên recordset>.CancelUpdate 


Làm tươi dữ liệu trong Recordset

Để làm tươi dữ liệu của bộ mẫu tin Recordset chúng ta có thể sử dụng cú pháp sau:

<tên recordset.ReQuery 


Sắp xếp, lọc dữ liệu

Để sắp xếp dữ liệu có trong một bộ mẫu tin chúng ta gán giá trị cho thuộc tính Sort theo cú pháp sau:

<tên recordset>.Sort = "<tên trường> [DESC], <tên trường 2> [DESC] 


Ví dụ dòng lệnh dưới đây sẽ sắp xếp dữ liệu của bộ mẫu tin rst theo thứ tự cột TENNV (tên nhân viên) tăng dần và sau đó là NGAYSINH giảm dần.

Rst.Sort = "TENNV, NGAYSINH DESC 


Trường hợp không cần sắp xếp dữ liệu nữa, chúng ta gán chuỗi rỗng cho thuộc tính Sort của Recordset
Rst.Sort="" 


Nếu muốn lọc dữ liệu của bộ mẫu tin theo một điều kiện nào đó, chúng ta có thể dùng thuộc tính Filter theo cú pháp sau:

<tên recordset>.Filter = "<điều kiện lọc>"
Khi không muốn lọc nữa, chúng ta gán cho thuộc tính này trị hằng adFilterNone hay chuỗi rỗng.

Chú ý:
Sau khi gán thuộc tính Filter, chỉ những mẫu tin thỏa mãn biểu thức lọc mới được hiển thị, vị trí hiện hành được di chuyển đến mẫu tin đầu tiên của nhóm hiển thị. Sau khi bỏ lọc, vị trí cũng được di chuyển về vị trí đầu trong danh sách các mẫu tin mới. Có thể lọc theo nhiều điều kiện và các điều kiện nối kết với nhau bằng AND, OR...có thể sử dụng các ký tự đại diện (*,?)

Tìm kiếm

Để tìm kiếm mẫu tin thỏa một điều kiện nào đó trong bộ mẫu tin Recordset chúng ta có thể sử dụng phương thức Find theo cú pháp sau:

<tên recordset>.Find = sCondition, [nRecordSkip], [nDirection], [startPos]


sCondition: là chuỗi chứa điều kiện cần tìm. Chuỗi này là một điều kiện đơn có dạng: <tên trường><tóan tử><giá trị>

• Các tóan tử thường được dùng là { =,>,<,>=,<=,<> và Like}. Giá trị trong điều kiện tìm có thể là một chuỗi ký tự được đặt trong cặp dấu nháy đơn '', một con số hay một giá trị ngày nằm giữa hai ký tự # #.

nRecordSkip: là một giá trị tùy chọn chỉ ra số mẫu tin sẽ được bỏ qua trước khi bắt đầu việc tìm kiếm. Tham số này thường được dùng để tìm tiếp theo điều kiện cũ sau khi đã tìm thấy một mẫu tin thỏa điều kiện. 

nDirection: là tham số chỉ ra hướng tìm. Mặc nhiên, tham số này sẽ có trị là 1 hay adSearchForWard (tìm theo hướng tới). Khi cần tìm theo hướng ngược lại, chúng ta có thể dùng giá trị -1 hay adSearchBackWard.

startPos: là tham số chỉ ra vị trí bắt đầu tìm. Mặc nhiên lệnh Find sẽ tìm từ vị trí hiện hành (adBookmarkCurrent). Khi cần tìm từ đầu hay tìm ngược từ cuối, chúng ta phải dùng các hằng sau: adBookmarkFirstadBookmarkLast.

Nếu tìm thấy, mẫu tin đầu tiên thỏa mãn điều kiện tìm sẽ trở thành mẫu tin hiện hành. Ngược lại, mẫu tin hiện hành là ở vị trí EOF nếu tìm tới hoặc ở vị trí BOF nếu đang tìm theo chiều ngược.

Đọan chương trình dưới đây sẽ tìm mẫu tin có trường NGAYLV trước ngày 1/1/1977 trong bộ mẫu tin rst:

sCondition = "NGAYLV<#1/1/1977#
vBookmark = rst.Bookmark
rst.Find sCondition,,,adBookmarkFirst
If rst.EOF Then
 Msgbox "Không tìm thấy"
 rst.Bookmark = vBookmark
Else
 Msgbox "Đã tìm thấy"
End If


Đối tượng Field của Recordset

Mỗi cột dữ liệu trong bộ mẫu tin Recordset được gọi là trường hay Field. Chúng ta thường sử dụng các thuộc tính sau của đối tượng Field:

DefinedSize: kích thước khai báo của Field trên nguồn dữ liệu.

Name: tên của Field.

OriginalValue: chỉ ra giá trị của Field, trước khi xảy ra sự thay đổi và chưa được cập nhật.

Type: kiểu dữ liệu của Field được khai báo trên nguồn dữ liệu.

Value: giá trị của Field, đây là thuộc tính mặc nhiên của Field.

Tập hợp Fields của Recordset

Khi muốn tham chiếu đến tập hợp các trường dữ liệu của recordset, chúng ta sử dụng tập họp Fields. Đọan chương trình sau đây sẽ duyệt qua các trường có trong bộ mẫu tin rst, lấy tên và kiểu dữ liệu của chúng đưa vào Combobox có tên là cmbTruong và cmbKieu:

Dim fld As ADODB.Field
For Each fld In rst.Fields
 cmbTruong.AddItem fld.Name
 cmbKieu.AddItem fld.Type
Next fld
cmbTruong.ListIndex=0 'Chọn mục đầu tiên


Khai báo với từ khóa WithEvents

Trong quá trình làm việc, bên cạnh nhu cầu khởi tạo một biến kiểu bộ mẫu tin ADODB.Recordset động trong chương trình, đôi lúc chúng ta còn cần phải sử dụng các xử lý biến cố liên quan đến biến bộ mẫu tin này (ví dụ như biến cố MoveComplete,...). Muốn như vậy chúng ta phải khai báo biến với từ khóa WithEvents theo cú pháp sau đây:

Dim | Public] WithEvents rst As ADODB.Recordset


Ví dụ sau đây sẽ lấy dữ liệu từ Access database tên budget.mdb. Database này có chứa một bảng tên Budget, có bảy trường dữ liệu: Division, Department, Category, Item, Month, Budget, Actual. Ví dụ này chỉ lấy các dữ liệu có trường Division = 'N. America' và Item = 'Lease'.

Sub ADO_Demo()
Dim DBFullName As String
Dim Cnct As String, Src As String
Dim Connection As ADODB.Connection
Dim Recordset As ADODB.Recordset
Dim Col As Integer
Cells.Clear
'Thông tin đường dẫn của dữ liệu
DBFullName= ThisWorkbook.Path & "budget.mdb"
'Mở connection
Set Connection = New ADODB.Connection
Cnct = "Provider=Microsoft.Jet.OLEDB.4.0; "
Cnct = Cnct & "Data Source=" & DBFullName & ";"
Connection.Open ConnectionString:=Cnct
'Tạo Recordset
Set Recordset = New ADODB.Recordset
With Recordset
'Lọc
Src = "SELECT * FROM Budget WHERE Item = 'Lease' "
Src = Src & "and Division = 'N. America'"
.Open Source:=Src, ActiveConnection:=Connection
'Điền tên trường vào
For Col=0 to Recordset.Fields.Count-1
 Range("A1").Offset(0,Col).Value=Recordset.Fields(Col).Name
Next
'Đưa recordset ra
Range("A1").Offset(1,0).CopyFromRecordset Recordset
End With
'Giải phóng biến và đóng Connection
Set Recordset = Nothing
Connection.Close
Set Connection = Nothing
End Sub


Vâng, thế đấy. Nếu bạn chịu khó dùng ADO trong các ứng dụng Excel của bạn tôi tin rằng ứng dụng của bạn sẽ thao tác dễ dàng hơn, nhanh hơn, bảo mật hơn, môi trường nhiều người dùng... Chúc các bạn thành công.

St from Lê Văn Duyệt

1 nhận xét: