Ch

ng M i Lăm - L p trình v i k thu t DAO

ươ

ớ ỹ

ườ

Reference DAO

ầ ả ớ c. Ta s ữ ầ ướ ư ậ ế ở ộ ự ư ệ ế ạ

ộ i đây. (M t ướ Trong bài n y ta s h c nh ng cách l p trình căn b n v i MS Access database qua ậ ẽ ọ ẽ k thu t DAO mà không c n dùng đ n ế Control Data nh trong bài tr ỹ c n đ n vài Objects trong th vi n DAO, do đó n u b n m m t d án VB6 m i thì ớ ầ hãy dùng Menu Command Project | References... đ ch n ể ọ Microsoft DAO 3.51 Object Library b ng cách click cái checkbox bên trái nh trong hình d ư cách đ nh tên c a Object n y là nh câu "th ng cha cua ĐÀO 35 con dê" ). ằ ủ ể ầ ằ ớ ớ

ủ myDatabase cho m tộ ẽ Ở đây ta nói t v i Database và Recordset ệ ớ ộ ể ạ DAO đ phân bi ể ạ ADO (ActiveX Data Object) sau n y. ầ Đ ý là Intellisense giúp ta trong t code: Sau đó trong code c a Form chính ta s declare variable instance c a ủ DAO database và variable myRS cho m t ộ DAO recordset. rõ Database và Recordset là thu c lo i thu c lo i ộ lúc vi ế

b n hãy đ t lên Form chính, tên ờ ạ ặ ớ Bây gi Published, ISBN và Publisher ID. K đó cho thêm 4 textboxes t frmDAO, 4 labels v i captions: ươ ứ Title, Year ng ng và đ t tên ặ ế

chúng là txtTitle, txtYearPublished, txtISBN và txtPublisherID.

c loaded, nó s l y v t ố ề ớ ượ ẽ ấ table Titles theo th t ộ database m t (alphabetical ề ừ v m u t ứ ự ề ẫ ự Đi u ta mu n làm là khi Form m i đ t c records trong Recordset ch a t ứ ấ ả order) c a ủ field Title và hi n th record đ u tiên. ể ầ ị

Dùng keyword SET

' Open main database Set myDB = OpenDatabase(AppFolder & "BIBLIO.MDB")

ướ ế c h t là m m t Database Object d a vào tên đ y đ (full path name) ự ầ ủ ở ộ Chuy n tr ệ c a Access database: ủ

ữ Set trong câu code trên. Đó là vì myDB là m t ộ Pointer đ n m t Object. ế ư ộ ề ẽ ầ ầ ộ ỉ ị ả ữ ể ằ Đ ý ch ộ ể ư ấ M c d u t rày v sau ta s dùng myDB nh m t Database theo cách gi ng nh b t ố ặ ầ ừ đâu đ n thì c variable thu c data type nào khác, nh ng khi ch đ nh l n đ u là nó t ế ừ ư ứ ta dùng ch Set, đ nói r ng th t ra myDB không ph i là Object Database, nh ng là ư Pointer đ n Object Database. Đi m n y càng nói đ n càng khó hi u. ậ ể ế ế ể ầ

ầ ộ ớ ể ứ ầ c nó t ừ ậ ượ ộ ị ư ể ắ ẫ ị ấ ị ộ ấ ứ memory address ch đ n ( ư ả Đ i khái là VB6 runtime dynamically allocates (dành ra cho khi c n) m t ph n trong ạ ủ execution c a b nh (memory) đ ch a Object Database khi ta nh n đ ộ Method OpenDatabase. D u v trí ch ch a Object Database trong b nh không ỗ ứ ớ ầ nh t đ nh, nh ng vì ta n m cái cán ch đ n v trí y nên ta v n có th làm vi c v i ệ ớ ấ ỉ ế ng. Cái cán y là value (tr s ) c a variable myDB. Vì value nó m t cách bình th ị ố ủ ườ n y không ph i là Object, nh ng nó ch a ỉ ế point to hay ầ refer to) Object Database, nên ta g i nó là Pointer. ọ

ộ ấ ậ ệ i Operating System ậ ớ ả ạ ầ ầ ạ ế ệ ả ạ ỏ ữ ữ ư ả i allocate ữ ể i memory không n th a thì có ầ ầ ế L n l n ả memory t. ng y là ấ ệ ượ ư ữ ẽ ọ ề ữ ố ậ ườ trong h u tr ườ ệ ậ ở L p trình dùng Pointer nói chung r t linh đ ng là hi u năng trong các ngôn ng nh C, Pascal, C++ ,v.v.. Tuy nhiên, l p trình viên ph i nh tr l ph n memory mình dùng khi không còn c n nó n a đ Operating System l cho Object khác. N u công vi c qu n lý dùng l ổ nh ng m nh memory n m lang bang mà Operating Sytem không bi ằ Operating System s không còn memory d n a. Ta g i hi n t leakage (r )ỉ . Các ngôn ng sau n y nh Java, C# đ u không dùng Pointer n a. ữ ư ầ ặ ng h p đ c Visual Basic không mu n l p trình viên dùng Pointer. Ch trong vài tr ợ ỉ ra cho ta th y th t ra bi ng VB6 Runtime dùng t VB6 m i l ậ ấ ng h p n y. Pointer, nh trong tr ợ ớ ộ ư ườ ầ

'Open recordset Set myRS = myDB.OpenRecordset("Select * from Titles ORDER BY Title")

ự ư ậ ế ộ ộ ươ ỉ ng t ị Set khi nh v y, vì Recordset là m t Pointer đ n m t Object, ta cũng dùng ề ừ Method OpenRecordset c a database ộ ủ ấ T ch đ nh m t DAO Recordset l y v t myDB.

ạ ộ L nhệ t c m i fields (columns) ( Select ấ ấ ả ọ ị Table Titles ( from Titles) làm m t Recordset và sort các records ừ ủ ộ Cái parameter lo i String ta dùng cho method OpenRecordset là m t (Statement) SQL. Nó ch đ nh cho database l y t ỉ *) c a m i record t ỗ trong Recordset y theo alphabetical order c a field Title ( ORDER BY Title). ủ ấ

ớ có Recordset r i, ta có th hi n th chi ti ộ ị ố c. Bây gi ờ ấ t c a ế ủ ề ấ ự ồ ộ ư property Recordset c a m t Control Data mà ủ ể ể ể i đây: Nh là Recordset n y cũng gi ng nh ầ ta dùng trong bài tr ướ record đ u tiên n u Recordset y có ít nh t m t record. Ta ki m tra đi u y d a vào ấ ế ầ property RecordCount c a Recordset nh trong code d ư ướ ủ

Private Sub Form_Load() ' Fetch Folder where this program EXE resides AppFolder = App.Path ' make sure it ends with a back slash If Right(AppFolder, 1) <> "\" Then AppFolder = AppFolder & "\" ' Open main database Set myDB = OpenDatabase(AppFolder & "BIBLIO.MDB") 'Open recordset Set myRS = myDB.OpenRecordset("Select * from Titles ORDER BY Title") ' if Recordset is not empty then display the first record If myRS.RecordCount > 0 Then myRS.MoveFirst ' move to first record Displayrecord ' display details of current record End If End Sub

Private Sub Displayrecord() ' Assign record fields to the appropriate textboxes With myRS ' Assign field Title to textbox txtTitle txtTitle.Text = .Fields("Title") txtYearPublished.Text = .Fields("[Year Published]") txtISBN.Text = .Fields("ISBN") txtPublisherID.Text = .Fields("PubID") End With End Sub

current record Record ủ ể ằ ủ ị Sau khi dùng method MoveFirst c a Recordset đ position ở đ u tiên, ta hi n th tr s các fields c a record b ng cách assign chúng vào các ể ầ textboxes c a Form nh sau: ị ố ư ủ

ể ả ặ ữ ồ ườ ư ể ợ

Đ ý vì field hai d u ngo c vuông ( ấ ị ặ b n đ t tên database field trong lúc thi ặ ạ nhau, đ ng đ r i ra. Thí d nh dùng Year Publshed g m có hai ch nên ta ph i đ t tên c a field y gi a ữ ủ ấ []). Đ tránh b phi n ph c nh trong tr ng h p n y, khi ầ ứ ề ữ ạ ớ i v i t k m t table hãy dán dính các ch l ế ế ộ YearPublished thay vì Year Published. ụ ư ể ờ ừ

Các nút di chuy nể

ng v i c a m t Control Data, b n hãy đ t lên ng đ ố ớ ủ ươ ươ ạ ặ ộ

Mu n có các nút Navigators t Form 4 buttons mang tên CmdFirst, CmdPrevious, CmNext và CmdLast v iớ captions: <<, <, >, >>.

Private Sub CmdNext_Click() myRS.MoveNext ' Move to next record ' Display record details if has not gone past the last record If Not myRS.EOF Then Displayrecord ' display details of current record Else myRS.MoveLast ' Move back to last record End If End Sub

ầ ừ ả ả ơ ố ể ể ầ ả ố EOF có trở ở Code cho các nút n y cũng đ n gi n, nh ng ta ph i coi ch ng khi user mu n di ư chuy n quá record cu i cùng hay record đ u tiên. Ta ph i ki m tra xem thành True khi user click CmdNext, hay BOF có tr thành True khi user click CmdPrevious:

Private Sub CmdPrevious_Click() myRS.MovePrevious ' Move to previous record ' Display record details if has not gone past the first record If Not myRS.BOF Then Displayrecord ' display details of current record Else myRS.MoveFirst ' Move back to first record End If End Sub

Private Sub CmdFirst_Click() myRS.MoveFirst ' Move back to first record Displayrecord ' display details of current record End Sub

Private Sub CmdLast_Click() myRS.MoveLast ' Move back to last record Displayrecord ' display details of current record End Sub

ng trình b n s th y nó hi n th chi ti ươ ạ ẽ ấ ị ế ủ ớ t c a Record đ u tiên khác v i ầ Khi ch y ch ạ trong bài tr c đây vì các records đã đ ể c sorted: ướ ượ

n c a mình xem chúng làm ử ườ ủ B n hãy th dùng các Navigator buttons cây nhà, lá v vi c có đúng không. ạ ệ

ớ ế ạ ử ổ ể ế ộ t b n có đ ý là dù user có vô tình s a đ i m t chi ti ậ ị ậ ế ớ T i đây, không bi t nào trong ể các textboxes, không có record nào b c p nh t hóa trong database khi user di chuy n t record n y đ n record khác. Lý do là các Texboxes không có Data Bound v i các ầ ừ Fields c a Recordset. ủ

Thêm b t các Records

ng trình trong bài r i, ta s thêm ph ố ồ ớ ng ti n đ thêm (add), b t ươ ẽ ệ ể cmdEdit, cmdNew, b n hãy đ vào Form 5 buttons tên: ờ ạ Gi ng nh ch ư ươ (delete) các records. Bây gi ể cmdDelete, cmdUpdate và cmdCancel.

ng trình tr c ta dùng Data1.Recordset thì bây gi ta dùng ươ ướ ờ Ch nào trong ch ỗ myRS.

i Editing có tr s False hay True tùy ẽ ạ Sub SetControls v i parameter ị ố ớ ị Ta s dùng l theo user đang Browse hay Edit. Trong Browse mode, các Textboxes b Locked (khóa) và các nút cmdUpdate và cmdCancel tr nên b t l c. Trong Edit mode, các ấ ự ở

c unlocked (m khóa) và các nút ượ ở cmdNew, cmdDelete và cmdEdit trở Textboxes đ nên b t l c. ấ ự

đây không có Data Binding nên đ i cho đ n khi ợ ở ậ ế

ỉ ầ ớ ệ ữ ộ ị ố ộ ắ ộ ệ ữ ế ộ Update (c p nh t hóa) ta m iớ Vì ậ đ t Recordset vào AddNew hay Edit mode. Do đó ta ch c n nh là khi user edits là ớ ặ đang Edit m t record hi n h u hay thêm m t Record m i. Ta ch a tr s Boolean y ấ ứ trong variable AddNewRecord. N u user s p thêm m t record m i thì ớ ế AddNewRecord = True, n u User s p Edit m t record hi n h u thì ắ AddNewRecord = False.

' If Editing existing record then AddNewRecord = False ' Else AddNewRecord = true Dim AddNewRecord As Boolean

Private Sub ClearAllFields() ' Clear all the textboxes txtTitle.Text = "" txtYearPublished.Text = "" txtISBN.Text = "" txtPublisherID.Text = "" End Sub

Private Sub cmdNew_Click() ' Remember that this is Adding a new record AddNewRecord = True ' Clear all textboxes ClearAllFields ' Place controls in Edit Mode SetControls (True) End Sub

Private Sub CmdEdit_Click() ' Place controls in Edit Mode SetControls (True) ' Remember that this is Editing an existing record AddNewRecord = False End Sub

ớ ằ ộ ắ ằ ả ự Ngoài ra, khi User s p thêm m t record m i b ng cách click nút New thì ta ph i t ắ clear (làm tr ng) h t các textboxes b ng cách assign Empty string vào text property ế c a chúng nh sau: ủ ư

Private Sub CmdCancel_Click() ' Cancel update SetControls (False) ' Redisplay details or current record Displayrecord End Sub

ế Ở ọ method ỉ đây ta ch t c a current record, t c là h y b nh ng gì user đang đánh i chi ti ủ ỏ ữ ế ủ ị ạ ứ N u user clicks Cancel trong khi đang edit các textboxes, ta không c n g i ầ CancelUpdate vì Recordset ch a b đ t vào AddNew hay Edit mode. ư ị ặ c n hi n th l ể ầ vào:

ạ ị ể ể ả ộ ắ ằ Lúc user clicks Update, b n có d p đ ki m tra data xem có field nào b b tr ng ị ỏ ố (nh t là ấ g i ọ Function GoodData. N u GoodData tr l Primary Key ISBN b t bu c ph i có tr s ) hay có gì không valid b ng cách ị ố ế i m t tr s False thì ta không xúc ti n ộ ị ố ả ạ ế

ệ ả ề ị ố ế ặ v i vi c Update. N u GoodData tr v tr s True thì ta đ t Recordset vào AddNew ớ hay Edit mode tùy theo tr s c a Boolean variable AddNewRecord. ị ố ủ

Private Function GoodData() As Boolean ' Check Data here. If Invalid Data then GoodData = False GoodData = True End Function

Private Sub CmdUpdate_Click() ' Verify all data, if Bad then do not Update If Not GoodData Then Exit Sub ' Assign record fields to the appropriate textboxes With myRS If AddNewRecord Then .AddNew ' Place Recordset in AddNew Mode Else .Edit ' Place Recordset in Edit Mode End If ' Assign text of txtTitle to field Title .Fields("Title") = txtTitle.Text .Fields("[Year Published]") = txtYearPublished.Text .Fields("ISBN") = txtISBN.Text .Fields("PubID") = txtPublisherID.Text ' Update data .Update End With ' Return controls to Browse Mode SetControls (False) End Sub

t c a m t Record ta ph i assign t ng Field vào textbox, ố ể ả ị khi Update ta ph i làm ng ư ờ ộ ượ ạ ứ c l ng ng. Sau cùng ta g i ừ ủ ừ i, t c là assign property Text c a t ng ọ method Update c a recordset ủ ươ ứ i Browse mode: Gi ng nh khi hi n th chi ti ế ủ thì bây gi ả textbox vào Record Field t và cho các controls tr l ở ạ

Private Sub CmdDelete_Click() On Error GoTo DeleteErr With myRS ' Delete new record .Delete ' Move to next record .MoveNext If .EOF Then .MoveLast ' Display details of current record Displayrecord Exit Sub End With DeleteErr: MsgBox Err.Description Exit Sub End Sub

ộ t c a record đó nh sau: Cũng vì không có Data Binding, nên khi User Delete m t record, sau khi di chuy n ể qua record k ti p ta ph i t ế ế hi n th chi ti ị ả ự ể ế ủ ư

Tìm m t record ộ

t kê các sách có tiêu đ ch a m t ch hay câu nào đó, thí ố ữ ệ ề ứ ộ ể ọ ộ ằ ề Go. Ch ủ ể ẽ ấ ị t c a nó. Ti p theo đây, ta mu n li ế ụ ư ữ Guide". K đó user có th ch n m t sách b ng cách select tiêu đ sách d nh ch " ế y và click nút ng trình s locate (tìm ra) record c a sách y và hi n th chi ấ ươ ti ế ủ

b n hãy cho vào Form m t textbox tên ộ ờ ạ ộ ế ộ fraSearch vào Form. Đ lên frame n y m t ộ ặ ể ể ề ị CmdClose và ẽ ộ t sách y. N u đ i ý, user s click nút ế ẽ ế ấ ổ ị txtSearch và m t Image tên Bây gi ImgSearch. K đó đ t m t frame tên ầ ể listbox tên List1 đ hi n th tiêu đ các sách, và hai buttons tên CmdGo, v i caption Close và Go. Sau khi select m t sách trong List1, user s click ớ nút Go đ hi n th chi ti ế Close đ làm bi n ể ể ể m t frame fraSearch. ấ

property ầ ầ ườ ủ ng frame fraSearch ch hi n ra khi c n, nên lúc đ u hãy set ộ ố ỉ ệ ẽ ể ị ể ọ

Bình th ạ Visible c a nó thành False. Ta s cho ImgSearch hi n th hình m t ng dòm nên b n hãy click vào bên ph i ả property Picture trong Properties Window đ ch n Icon BINOCULR.ICO t folder E:\Program Files\Microsoft Visual ừ Studio\Common\Graphics\Icons\Misc:

Private Sub ImgSearch_Click() ' Show Search Frame fraSearch.Visible = True Dim SrchRS As DAO.Recordset Dim SQLCommand As String ' Define SQL statement

ISBN. Khi user select m t sách ta mu n bi ủ ộ ố ủ ỗ ị ể ộ ủ ờ ỉ ẽ ậ ướ ể ế Cái Primary Key c a table Titles là t ISBN c a sách y đ locate (đ nh ch ) nó trong Recordset myRS. Do đó trong khi ấ ộ thêm tiêu đ c a m t sách vào List1, ta đ ng th i thêm ISBN c a sách y vào m t ề ủ ấ ồ ng, nên hãy set property Listbox th hai tên List2. Ta ch s dùng List2 sau h u tr ứ ườ Visible c a nó thành False. D i đây là code đ load tiêu đ sách và ISBN vào các ề ủ Listboxes:

SQLCommand = "Select * from Titles where Title LIKE '" & "*" & txtSearch & "*" & "' ORDER BY Title" ' Fetch all records having Title containing the text pattern given by txtSearch Set SrchRS = myDB.OpenRecordset(SQLCommand) ' If Recordset is not Empty then list the books' titles in List1 If SrchRS.RecordCount > 0 Then List1.Clear ' Clear List1 ' We use List2 to contain the Primary Key ISBN corresponding to the books in List1 List2.Clear ' Clear List2 With SrchRS ' Iterate through the Recordset until EOF Do While Not SrchRS.EOF ' Display Title in List1 List1.AddItem .Fields("Title") ' Store corresponding ISBN in List2 List2.AddItem .Fields("ISBN") .MoveNext ' Move to next record in the Recordset Loop End With End If End Sub

Khi user Click ImgSearch v i text pattern là ch i đây: ữ Guide, ta s th y hình d ẽ ấ ớ ướ

ỗ ượ ữ hai bên. Wildcard character là ch có (hay không ở ng h p n y có nghĩa là h có ch Guide trong tiêu ễ ầ ự ọ ự ầ Không có đâu. Ngoài ra s ch n l a n y ợ ằ ở Trong SELECT statement bên trên ta dùng operator LIKE trên text pattern, chữ Guide, có wildcard character (*) c. Trong tr có) ch gì cũng đ ườ ữ đ sách là đ t nó n m c, không c n bi ầ ế ượ ề ữ guide, Guide hay GUIDE đ u đ Case Sensitive, t c là ch c c . ề ượ ả ứ

Private Sub CmdGo_Click() Dim SelectedISBN As String Dim SelectedIndex As Integer Dim Criteria As String ' Index of line selected by user in List1 SelectedIndex = List1.ListIndex ' Obtain corresponding ISBN in List2

ể ị ủ ẽ method FindFirst c a Recordset myRS đ đ nh ng ng v i tiêu đ ớ ươ ứ ị ố ề c ch n trong List1 nh sau: Khi user clicks nút Go, ta s dùng ch c a record có tr s Primary Key là hàng text trong List2 t ỗ ủ d ượ ư ọ

SelectedISBN = List2.List(SelectedIndex) ' Define Search criteria - use single quotes for selected text Criteria = "ISBN = '" & SelectedISBN & "'" ' Locate the record, it will become the current record myRS.FindFirst Criteria ' Display details of current record Displayrecord ' Make fraSearch disappeared fraSearch.Visible = False End Sub

ư ạ ả ộ ớ ố L u ý là trong string Criteria, vì ISBN thu c lo i text, ch không ph i là m t con s , ộ nên ta ph i k p nó gi a hai d u ngo c đ n. ặ ơ ữ ả ẹ ấ

Bookmark

ế record n y đ n record khác trong Recordset, đôi khi ta mu n đánh ể ừ ộ ủ ố ằ i. Ta có th th c hi n đi u y b ng ị ẽ ở ạ ể ự ề ấ ệ ị Khi di chuy n t d u v trí c a m t record đ có d p s tr l ấ cách ghi nh ớ Bookmark c a Recordset. ầ ể ủ

Dim LastBookMark As Variant

ớ ị ể ố ầ ạ LastBookmark ấ ủ Go Back. B n hãy thêm vào Form m t button tên ộ Go Back. Ta s thêm m t variable tên ộ ẽ Thí d khi user clicks nút Go, ta mu n nh v trí c a record lúc y đ sau n y quay ụ i khi User clicks nút tr l ở ạ CmdGoBack v i Caption ớ Variant: lo i data type ạ

' Remember location of current record LastBookMark = myRS.BookMark CmdGoback.Visible = True

ầ ỉ ở Lúc đ u button CmdGoBack invisible, và ch tr nên visible sau khi user clicks nút Go. Ta thêm các hàng codes sau vào Sub CmdGo_Click() nh sau: ư

Private Sub CmdGoback_Click() ' Reposition record to last position myRS.BookMark = LastBookMark ' Redisplay details or current record Displayrecord End Sub

D i đây là code đ quay tr l i v trí current record tr c đây trong Recordset: ướ ở ạ ị ể ướ

LastModified

Private Sub CmdLastModified_Click() ' Reposition record to last position myRS.BookMark = myRS.LastModified ' Redisplay details or current record Displayrecord

c s a đ i hay thêm vào trong ớ ượ ử ổ ừ ạ ầ ộ ỉ ệ Last Modified. Button n y ch hi n ra sau khi user ầ ớ ừ ượ c LastModified là vi tr c a record v a m i đ ị ủ Recordset. Đ th đi u n y b n hãy thêm m t button invisible tên ể ử ề CmdLastModified v i caption là ớ clicks Update. B t c lúc nào b n Click nút CmdLastModified, record m i v a đ ấ ứ s a đ i hay thêm vào s hi n th : ử ổ ẽ ể ạ ị

End Sub

c thi t k : D i đây là hình c a Form lúc đang đ ủ ướ ượ ế ế

Ta s h c k thu t ADO (ActiveX Data Object) trong bài t i. ẽ ọ ỹ ậ ớ