Đánh giá chủ đề:
  • 1 Votes - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Sử dụng Class Module và Kết nối dữ liệu SQL SERVER trong Access VBA
#11
Chào các Bạn,

Hôm nay chúng ta sẽ trao đổi đến một công cụ để quản lý tập hợp các thành phần thuộc object do chúng ta tự tạo ra (bằng cách thức ta đã trao đổi trong các bài trước). Công cụ này được Access VBA gọi là Collection.

Trong Access VBA, Collection là một Object như một tập hợp các thành phần nhiều object xác định. Chẳng hạn như tập hợp từng dòng danh sách trong cùng 1 danh bạ vậy .

Collection trong Access VBA có 3 methods và 1 Property sau đây:

- Methods:
+ Add: dùng để thêm một thành phần vào Collection tự tạo. Chúng ta có thể dễ dàng truy xuất đến thành phần bất kỳ trong Collection này thông qua một khoá chỉ định, khoá này gọi là “Key”
+ Item: dùng để truy xuất đến 1 thành phần xác định thông qua 1 chỉ số index (hay là chỉ số thứ tự) của thành phần xác định đó trong Collection tự tạo
+ Remove: dùng để xoá 1 thành phần xác định khỏi Collection tự tạo thông qua chỉ số index hoặc key tương ứng của thành phần đó.

- Property:
+ Count: dùng để lấy tổng số thành phần đang có trong Collection tự tạo

Trong file ứng dụng minh họa, giả định chúng ta có nhu cầu cần xử lý một danh sách thỏa một điều kiện lọc xác định nào đó.
Cách làm khoa học nhất là sử dụng Collection để tập hợp danh sách đó lại, sau đó sẽ tùy nghi xử lý.
Với cách làm này, việc xử lý sẽ tách tập hợp danh sách này riêng ra khỏi file dữ liệu, tránh nặng nề cho các tác vụ khác trong môi trường nhiều người dùng trong mạng máy tính. Đồng thời ta cũng được lợi là danh sách (đã được lọc) ấy sẽ được lưu trữ tạm thời trong bộ nhớ máy tính (RAM) nên việc xử lý sẽ nhanh hơn.

Các Bạn xem ví dụ sau nhé:
Giả định ta muốn lấy toàn bộ danh sách đã được lọc trên form “frmContacts” để ghi vào 1 bảng dữ liệu đã được tạo trước đó (giả định bảng này tên là tblDs, với 2 cột dữ liệu: Id và Ten).
Ta sẽ phải làm 2 việc sau đây:
1. Ta viết thủ tục sau để lấy dữ liệu vào bảng tblDs, có nội dung như sau:
Mã:
Sub GetDataFromCollection(strSQL As String)
'
Dim sqlSt As String, sCri As String, vCount As Long
Dim MyRec As ADODB.Recordset
'
Dim MyObj As clsDanhba
Dim TestCol As Collection
Set TestCol = New Collection
'
Set MyRec = ProcessRecordset(strSQL)
'Sau đây ta sẽ duyệt MyRec để nạp các dòng danh sách cho TestCol (Collection)
Do Until MyRec.EOF
    Set MyObj = New clsDanhba
    MyObj.PopulatePropertiesFromRecordset MyRec
    TestCol.Add MyObj 'Thêm thành phần vào Collection với method Add
    MyRec.MoveNext
Loop

MyRec.Close
Set MyRec = Nothing
Set MyObj = Nothing
'
vCount = TestCol.Count 'Lấy tổng số dòng danh sách (thành phần) đã thêm vào Collection với Property Count

'Sau đây ta duyệt từng thành phần trong Collection TestCol để cho ghi vào bảng tblDs
'Hoặc Bạn có thể viết code khác để làm một việc nào đó khác
'Xin chú ý cách duyệt các thành phần của 1 Collection thông qua cấu trúc câu lệnh For Each ... Next

DoCmd.RunSQL "DELETE * FROM tblDs"

For Each MyObj In TestCol
    With MyObj
        DoCmd.Hourglass True
        DoCmd.RunSQL "INSERT INTO tblDs(Id, Ten) VALUES(" & .DanhbaId & ",'" & .Ten & "')"
        DoCmd.Hourglass False
    End With
Next

Set TestCol = Nothing

'Open Table tblDs
MsgBox "Danh sach nay co tat ca la: " & vCount & " nguoi"
DoCmd.OpenTable "tblDs", , acReadOnly

End Sub

2. Ta bổ sung thêm thiết kế cho form “frmContacts”, với:
+ 1 nút lệnh có caption là “Lấy Danh sách”
+ và thêm thủ tục sự kiện Click Even cho nút lệnh này như sau:
Mã:
...
GetDataFromCollection GetSQL
'Cho hien ket qua len form
Call RunSearch
...

Bạn nào muốn xem chứ ngại viết như trên thì tải về file ứng dụng từ link sau nhé:
http://www.mediafire.com/?o5krl1bznxpanjy

Như vậy ta đã khảo sát xong 1 trường hợp sử dụng Collection.
Cũng xin các Bạn lưu ý: có rất nhiều cách sử dụng Collection. Ở đây tôi chỉ trình bày 1 cách, các Bạn có thể tùy trường hợp và nhu cầu cụ thể để sử dụng thích hợp.

Trong bài sau, chúng ta sẽ tìm hiểu vấn đề nên thiết kế Form gắn kết với nguồn dữ liệu (Bound-Form) hay thiết kế Form không gắn kết với nguồn dữ liệu (UnBound-Form).
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , Minh Tiên
#12
Chào các Bạn,

Tôi vừa tìm lại được tài liệu + ứng dụng minh họa do tôi sưu tầm trước đây trên internet đề cập đến việc tạo và sử dụng các Object tự tạo (custom objects) và Collection tự tạo (custom collections) với Access VBA. Tất cả đều bằng tiếng Anh.
Link tải về: http://www.mediafire.com/?434diarb50ric4v

Qua tài liệu này ta sẽ thấy 1 cách khác trong việc sử dụng Collection.
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , Minh Tiên
#13
Chào các Bạn,

Hôm nay, xin trao đổi với các Bạn về Bound Form và UnBound Form

1. Bound Form là gì?
Bound Form là 1 form được gán Record Source xác định, nghĩa là Bound Form được gán với 1 nguồn dữ liệu xác định, nguồn dữ liệu đó có thể là 1 bảng (table) hoặc 1 truy vấn dữ liệu (Query), nói theo ngôn ngữ lập trình với ADO thì nguồn dữ liệu này là 1 Recordset.
Khi tạo 1 Form trong Access, nguồn dữ liệu được khai báo thông qua property “Record Source”.
Đặc điểm của Bound Form là nguồn dữ liệu được nạp và duy trì liên tục từ lúc Form được mở cho đến khi Form được đóng lại. Mọi việc xử lý dữ liệu, từ nạp dữ liệu nguồn, duyệt dữ liệu nguồn,... hầu như đều do Access làm thay ta hết thảy.

Với các Form được đặt ở chế độ cho phép thêm, xóa, hiệu chỉnh dữ liệu trong điều kiện nhiều người sử dụng cùng lúc (truy xuất cùng 1 nguồn dữ liệu) sẽ dễ dẫn đến tình trạng khi form đang ở tình trạng hiệu chỉnh 1 mẫu tin (Record) và chưa kết thúc công việc này sẽ dẫn đến việc Access tạm khóa mẫu tin này lại (record locked) cho đến khi kết thúc việc hiệu chỉnh dữ liệu (bằng việc cho lưu các thay đổi hoặc phục hồi lại như cũ – Undo). Khi mẫu tin bị Access tạm khóa nếu lại có ai đó cũng đồng thời hiệu chỉnh mẫu tin này, Access sẽ ngăn lại và hiện thông báo cảnh báo. Nếu ta lập trình không khéo để bẩy sự kiện truy xuất trùng này sẽ dễ dàng dẫn đến làm hỏng nguồn dữ liệu đang nạp.

Các Bạn hình dung tình huống sau xem điều gì sẽ xảy ra nhé: nhân viên A đang mở mẫu tin xác định ra để hiệu chỉnh, và đang hiệu chỉnh nữa chừng chưa lưu lại các thay đổi thì bổng chột bụng cần phải “giải quyết” ngay. Thế là mẫu tin bị treo ở đó cho đến khi nhân viên A quay lại và có thao tác thích hợp. Mọi người khác phải đành bó tay khi cần làm gì đó với mẫu tin này. Lỡ nhân viên A quên quay lại để có thao tác chấm dứt cái sự nữa chừng bị treo lại kia thì sao? Bó tay đó các Bạn.

2. UnBound Form là gì?
Ngược với Bound Form, UnBound Form là form không gắn với 1 nguồn dữ liệu xác định nào cả.
Vậy làm sao UnBound Form hiển thị được thông tin ta cần đến, và làm sao để ta có thể thêm mới hoặc hiệu chỉnh nội dung một mẫu tin nào đó trong 1 nguồn dữ liệu xác định?
Nguyên tắc ở đây là: khi nào cần thì cho kết nối với dữ liệu nguồn, xong việc thì đóng kết nối lại.
- Việc kết nối với dữ liệu nguồn:
+ Có nhiều kiểu kết nối tùy theo mục đích của ta cần kết nối để làm gì? Chỉ để xem hay còn để hiệu chỉnh, cập nhật lại thông tin? Tùy theo đó mà ta lựa chọn kiểu kết nối thích hợp.
+ Mặt khác, cũng cần phải xác định rõ phạm vi kết nối, để tránh chiếm dụng vô ích tài nguyên bộ nhớ của máy tính; chẳng hạn như nếu ta chỉ cần xử lý danh sách với một phạm vi lọc nào đó (danh sách theo 1 vùng địa lý xác định được ghi trong địa chỉ của khách hàng có trong danh sách chẳng hạn), tránh việc nạp hết nguồn dữ liệu lên.
Với UnBound Form, việc truy xuất đến dữ liệu nguồn đều phải do ta tự làm lấy thông qua việc viết các thủ tục (procedure) để xử lý (từ việc nạp dữ liệu đến việc hiển thị, hiệu chỉnh, xóa, cập nhật thay đổi, ...). Đây chính là đặc điểm khác với Bound Form.

Rõ ràng, qua các đặc điểm của UnBound Form như trên đã phân tích, cho ta thấy UnBound Form thích hợp cho việc khai thác và xử lý nguồn dữ liệu trong môi trường nhiều người sử dụng cùng lúc (làm việc trên mạng máy tính), đặc biệt đối với dữ liệu có quy mô lớn (lớn về độ phức tạp và lớn về sức chứa vật lý)

3. Vậy, nên áp dụng Bound Form hay UnBound Form? Cái nào ưu việt hơn?
Câu trả lời ở đây là: lựa chọn phải tùy vào mục đích ta áp dụng để làm gì và trong hoàn cảnh cụ thể như thế nào?
Nếu chỉ với dữ liệu chạy cục bộ, chỉ có một người sử dụng trong cùng 1 thời gian và quy mô dữ liệu không lớn lắm thì lựa chọn áp dung Bound Form sẽ tốt hơn, vì dễ dàng và nhanh chóng.
Cái nào ưu việt hơn? cái nào giúp ta đạt được mục đích với chi phí ít nhất (tiền bạc, thời gian, công sức) là cái ưu việt hơn. Ở đây chúng ta cần suy niệm nguyên tắc của tiền nhân là “đừng bao giờ mổ gà bằng dao mổ trâu và ngược lại.”

Hẹn các Bạn trong bài sau ta sẽ tìm hiểu tiếp cách thức xử lý dữ liệu với 1 Unbound Form.
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , Minh Tiên
#14
(05-07-12, 12:27 PM)lehongduc Đã viết: Chào các Bạn,

Hôm nay, xin trao đổi với các Bạn về Bound Form và UnBound Form

1. Bound Form là gì?
Bound Form là 1 form được gán Record Source xác định,
............
2. UnBound Form là gì?
Ngược với Bound Form, UnBound Form là form không gắn với 1 nguồn dữ liệu xác định nào cả.
.....
3. Vậy, nên áp dụng Bound Form hay UnBound Form? Cái nào ưu việt hơn?
Câu trả lời ở đây là: lựa chọn phải tùy vào mục đích ta áp dụng để làm gì và trong hoàn cảnh cụ thể như thế nào?
Nếu chỉ với dữ liệu chạy cục bộ, chỉ có một người sử dụng trong cùng 1 thời gian và quy mô dữ liệu không lớn lắm thì lựa chọn áp dung Bound Form sẽ tốt hơn, vì dễ dàng và nhanh chóng.
Cái nào ưu việt hơn? cái nào giúp ta đạt được mục đích với chi phí ít nhất (tiền bạc, thời gian, công sức) là cái ưu việt hơn. Ở đây chúng ta cần suy niệm nguyên tắc của tiền nhân là “đừng bao giờ mổ gà bằng dao mổ trâu và ngược lại.”
Bài viết rất hay và câu nói rất chí lý! Mình thấy nhiều bạn cứ cố nhét thật nhiều VBA vào để có vẻ 'pro', nhưng thật ra chỉ vài câu query là giải quyết được vấn đề.Mình từng thấy 1 chương trình kế toán chỉ có code đọc số thành chữ là dùng VBA, còn lại toàn query và macro và "10 năm vẫn chạy tốt". Và cũng đúng như bạn phân tích, unbound đúng là xử lý tốt hơn Bound, nhưng các bạn cần cân nhắc hiệu quả kinh tế khi dùng nó!
Chữ ký của Noname 020
ღღღღღTài sản của Noname (View All Items) ღღღღღ
Reply
Những người đã cảm ơn quanghoasla
#15
(05-07-12, 02:14 PM)Noname Đã viết:
(05-07-12, 12:27 PM)lehongduc Đã viết: Chào các Bạn,

Hôm nay, xin trao đổi với các Bạn về Bound Form và UnBound Form

1. Bound Form là gì?
Bound Form là 1 form được gán Record Source xác định,
............
2. UnBound Form là gì?
Ngược với Bound Form, UnBound Form là form không gắn với 1 nguồn dữ liệu xác định nào cả.
.....
3. Vậy, nên áp dụng Bound Form hay UnBound Form? Cái nào ưu việt hơn?
Câu trả lời ở đây là: lựa chọn phải tùy vào mục đích ta áp dụng để làm gì và trong hoàn cảnh cụ thể như thế nào?
Nếu chỉ với dữ liệu chạy cục bộ, chỉ có một người sử dụng trong cùng 1 thời gian và quy mô dữ liệu không lớn lắm thì lựa chọn áp dung Bound Form sẽ tốt hơn, vì dễ dàng và nhanh chóng.
Cái nào ưu việt hơn? cái nào giúp ta đạt được mục đích với chi phí ít nhất (tiền bạc, thời gian, công sức) là cái ưu việt hơn. Ở đây chúng ta cần suy niệm nguyên tắc của tiền nhân là “đừng bao giờ mổ gà bằng dao mổ trâu và ngược lại.”
Bài viết rất hay và câu nói rất chí lý! Mình thấy nhiều bạn cứ cố nhét thật nhiều VBA vào để có vẻ 'pro', nhưng thật ra chỉ vài câu query là giải quyết được vấn đề.Mình từng thấy 1 chương trình kế toán chỉ có code đọc số thành chữ là dùng VBA, còn lại toàn query và macro và "10 năm vẫn chạy tốt". Và cũng đúng như bạn phân tích, unbound đúng là xử lý tốt hơn Bound, nhưng các bạn cần cân nhắc hiệu quả kinh tế khi dùng nó!

Quả thật là rất hay, phân tích cũng chí lý. Dùng Bound hay UnBound Form là tùy thuộc vào mục đích sử dụng của người dùng, cũng như việc dùng VBA hay macro, query cũng thế. Như đã có lần trao đổi trong bài viết dùng query để tinh tồn kho và lập thẻ kho tôi đã trao đổi : trong Access, hơn 90% vấn đề cần giải quyết ta có thể sử dụng query để truy vấn kết quả. VBA chỉ là để bảo mật CSDL tốt hơn khi chuyển sang MDE.
Cám ơn bạn Lê Hồng Đức đã chia sẻ kinh nghiệm của mình cho cộng đồng
Thân mến
Chữ ký của Xuân Thanh Trăm năm trước thì ta chưa gặp
Trăm năm sau biết gặp được không?
Cuộc đời sắc sắc không không
Thì thôi ta cứ hết lòng vì nhau
ღღღღღTài sản của Xuân Thanh (View All Items) ღღღღღ
Reply
Những người đã cảm ơn Noname , quanghoasla
#16
Chào các Bạn,

Hôm nay ta tiếp tục tìm hiểu xem cách thức xử lý dữ liệu với 1 UnBound Form như thế nào?

Với 1 UnBound Form ta cần phải giải quyết những nhu cầu sau đây:
1. Làm sao để nạp được nội dung dữ liệu cho hiển thị lên các ô dữ liệu trên Form?
2. Làm sao để cập nhật các thông tin (thêm hoặc lưu các thay đổi) đang có trên Form vào nguồn dữ liệu?
3. Làm sao để xoá 1 mẫu tin xác định?
4. Làm sao để duyệt qua lại các mẫu tin của nguồn dữ liệu và cho hiển thị chúng trên Form (như 1 Bound Form đã có sẵn qua các nút lệnh duyệt tới lui qua Navigation Buttons)?

Để đáp ứng được các nhu cầu nêu trên trước hết ta cần chú ý một số vấn đề mang tính nguyên tắc trong thiết kế UnBound Form như sau:

1. Việc đặt tên các Control trong UnBound Form:
Đặc điểm của UnBound Form là không gắn với nguồn dữ liệu xác định thông qua property “Record Source”, và các Controls trong Form (TextBox, ComboBox, ListBox, …) này cũng không gắn với nguồn dữ liệu xác định thông qua property “Control Source”.

Do vậy, khi đặt tên các Controls này ta phải chú ý đặt tên sao cho thể hiện mối liên hệ trực tiếp đến các cột dữ liệu trong nguồn dữ liệu ta cần xử lý, chẳng hạn như với file ứng dụng minh hoạ, ta thấy bên trong form “frmContacts”:
+ TextBox mang tên “txtTen” sẽ được dùng để hiển thị “Tên” của từng người trong danh bạ.
+ TextBox mang tên “txtHoChulot” sẽ được dùng để hiển thị “Họ và chữ lót” của từng người trong danh bạ.

Điều đó giúp ta tránh được việc nhầm lẫn khi gán nội dung thông tin chi tiết tương ứng lên các Control này khi viết các thủ tục xử lý dữ liệu.

2. Việc cho hiển thị thông tin trên UnBound Form:
Với ứng dụng chạy trong môi trường nhiều người dùng (qua mạng máy tính) ta phải hết sức tiết kiệm tài nguyên của máy tính (bao gồm cả không gian trống của bộ nhớ và cường độ làm việc của CPU), dù máy tính được trang bị mạnh đến cỡ nào đi nữa cũng không được lơ là việc tiết kiệm tài nguyên. Bởi vấn đề ở đây không chỉ là tiết kiệm thôi đâu, mà còn là vấn đề tránh xung đột khi xử lý dữ liệu.
Do vậy, ta chỉ cho hiển thị thông tin khi cần và chỉ nạp nguồn dữ liệu trong phạm vi vừa đúng với nhu cầu cần xử lý (không được thừa hoặc thiếu). Chẳng hạn như khi mở Form, nếu không phải là nhu cầu hiển thị kết quả tìm kiếm thì ta không nên nạp bất kỳ thông tin gì lên Form, nghĩa là để Form trống ở tình trạng sẵn sàng nhận nội dung ta nhập vào. Làm như vậy việc nạp Form lên sẽ rất nhanh, có thể nói là tức thì.

Bây giờ ta xét từng nhu cầu xử lý dữ liệu:

1. Làm sao để nạp được nội dung dữ liệu cho hiển thị lên các ô dữ liệu trên Form?
Thường để làm việc này ta cần phải qua các thủ tục sau:
+ Kết nối đến nguồn dữ liệu cần xử lý (Database)
+ Cho nạp tập hợp các mẫu tin trong phạm vi cần xử lý (Recordset)
+ Nạp thông tin chi tiết của mẫu tin đầu tiên vào các ô dữ liệu có liên quan trên form (Record)

Xét ứng dụng minh hoạ với form “frmContacts” ta thấy:
+ Để kết nối đến nguồn dữ liệu (Database) ta có thủ tục “OpenDbConnection” trong module “modQuanlyDulieu”
+ Để nạp tập hợp mẫu tin hiện ta đang có thủ tục “RetrieveDanhba” trong class module “clsDanhba” như một method của Object tự tạo “clsDanhba”.

Thủ tục “RetrieveDanhba” hiện có cho nạp tập hợp mẫu tin (Recordset) là toàn bộ bảng dữ liệu “tblDanhsach”. Ta cũng đã biết bảng “tblDanhsach” có trên 15.000 mẫu tin. Vậy là ta đã cho nạp hết trọi tập hợp trên 15.000 mẫu tin này.

Vấn đề cần được quan tâm đánh giá ở đây là: ta nạp khối lượng mẫu tin to đùng như vậy để làm gì?
Xét hết trọi các thao tác và nhu cầu hiển thị thông tin trên form “frmContacts” ta thấy:
Ngoài việc để biết bảng dữ liệu có tổng số mẫu tin là bao nhiêu, còn lại chẳng để làm gì cho có lợi cả.
Vậy thì hà cớ gì ta lại tiêu tốn một lượng lớn tài nguyên của máy tính cho chỉ duy nhất có 1 mục đích như vậy. Nếu muốn lấy tổng số mẫu tin trong 1 bảng dữ liệu ta chỉ cần “SELECT Count( *) FROM <tên_bảng_dữ_liệu>” là được rồi kia mà.

Mặt khác ta cũng thấy rằng, với kiểu xài sang đó mỗi khi mở form “frmContacts” ta thấy phải mất bộn thời gian tính bằng giây thì form mới nạp xong.

Do đó, ta cần 1 giải pháp để chỉ nạp tập hợp mẫu tin trong phạm vi cần xử lý thôi.
Sau đây là 1 cách, theo đề nghị của tôi (Nếu các Bạn có giải pháp khác xin trao đổi thêm nhé):
Ta sẽ phải làm mấy công việc sau đây:
Việc thứ nhất:
- Để bảo toàn thủ tục đang có nhằm mục đích có cái mà đối chiếu so sánh thiệt hơn giữa các giải pháp, ta sẽ viết thêm 1 thủ tục, sao cho chỉ cần nạp 1 tập hợp khoảng chừng 100 mẫu tin thôi.
Tại sao tôi lại chọn 100 mẫu tin, mà không chọn ít hơn, thậm chí chỉ cần 1 là đủ, vì mỗi lần ta chỉ hiển thị được nội dung của 1 mẫu tin lên Form “frmContacts” thôi mà?
Ái dà, cũng phải có lý do đầy đủ và hợp lý chứ các Bạn nhỉ.
Là tôi nghĩ như thế này:
Việc cần phải nạp hơn 1 mẫu tin nhằm mục đích để minh họa cho các thao tác duyệt tập hợp mẫu tin trên form “frmContacts” thông qua các nút lệnh duyệt mẫu tin tơi lui.
Do vậy, nếu nạp ít quá sẽ khó hình dung tác dụng của các thủ tục duyệt mẫu tin.
Thủ tục được viết thêm như sau:
Mã:
Function BuildSQLSelectLimitDanhba(FromId, ToId) As String

    On Error GoTo HandleError
  
    Dim strSQLRetrieve As String
  
    sChemaName = GetSchemaTable("tblDanhsach")
  
    strSQLRetrieve = "SELECT * FROM " & sChemaName & ".tblDanhsach"
    strSQLRetrieve = strSQLRetrieve & " WHERE DanhbaId BETWEEN " & FromId & " AND " & ToId
    strSQLRetrieve = strSQLRetrieve & " ORDER BY DanhbaId"
  
    BuildSQLSelectLimitDanhba = strSQLRetrieve
  
    Exit Function

HandleError:
    GeneralErrorHandler Err.Number, Err.Description, DB_QUANLY, "BuildSQLSelectLimitDanhba"
    Exit Function

End Function
Các Bạn để ý thủ tục trên sẽ thấy ta SELECT bảng dữ liệu với 1 điều kiện trong câu lệnh WHERE xác định là chỉ chọn các mẫu tin liên tục bắt đầu từ Danhbaid = biến FromId đến DanhbaId = biến ToId.
Và ta sẽ điều chỉnh lại thủ tục “RetrieveDanhba” trong class module "clsDanhba" cho thích hợp như sau:
Mã:
Function RetrieveDanhba(WithLimit As Boolean, Optional FromId, Optional ToId) As ADODB.Recordset

'RetrieveDanhba: Truy xuat recordset cua Danhba thong qua cau lenh strSQLStatement

    On Error GoTo HandleError
    
    Dim strSQLStatement As String
    Dim rsCont As New ADODB.Recordset

    ‘Dòng ngay bên dưới là dòng để nạp chuỗi SELECT toàn bộ danh bạ
    'strSQLStatement = BuildSQLSelectDanhba

    ‘==== Nay ta REM nó lại để nạp đoạn code thay thế sau đây:======
    If WithLimit = True Then
        strSQLStatement = BuildSQLSelectLimitDanhba(FromId, ToId)
    Else
        strSQLStatement = BuildSQLSelectDanhba
    End If
    ‘============== HẾT ĐOẠN CODE MỚI ===============

    Set rsCont = ProcessRecordset(strSQLStatement)
  
    Set RetrieveDanhba = rsCont
  
    Exit Function

HandleError:
    GeneralErrorHandler Err.Number, Err.Description, CLS_DANHBA, "RetrieveDanhba"
    Exit Function

End Function
Việc thứ hai: là làm sao xem được tổng số mẫu tin trong bảng danh sách?
Ta phân tích nhu cầu thì thấy rằng đây là nhu cầu không cần thường xuyên, vậy ta sẽ làm việc này chỉ khi nào cần thôi.
- Tôi viết thêm thủ tục lấy tổng số mẫu tin trong bảng danh sách như sau:
+ Trước hết tôi khai báo 1 biến dùng chung cho toàn bộ ứng dụng chỉ tổng số mẫu tin trong bảng danh sách bằng câu lệnh khai báo sau:
Mã:
Public lngRecCount As Long
Tất nhiên là dòng khai báo trên nằm ở vùng Declarations của module “modQuanlyDulieu”
Và thủ tục được thêm như sau:
Mã:
Sub GetTotalRecCount()
Dim strSQLStatement As String
Dim rsSourceRec As ADODB.Recordset
strSQLStatement = BuildSQLSelectDanhba
Set rsSourceRec = ProcessRecordset(strSQLStatement)
lngRecCount = rsSourceRec.RecordCount
Set rsSourceRec = Nothing
End Sub

- Kế đó, tôi sẽ vẽ vời thêm vài nét trên hình hài của form “frmContacts” gồm có:
+ Thêm 1 ô kiểm (check-box) để ta đánh dấu chọn khi cần cho hiện tổng số mẫu tin của bảng dữ liệu.
+ Thêm 1 ô dữ liệu nữa để hiển thị “DanhbaId” của từng mẫu tin được nạp lên form. Ô này ta cho nó mờ đi bằng cách khai báo property “Enabled” là False (Hay “No”).
+ Thêm một nút lệnh vào nhóm các nút lệnh duyệt mẫu tin để nạp 100 mẫu tin khác khi cần và gán nó cái nhãn (caption) là “+100 Rec” cho dễ hiểu.
Cứ mỗi lần bấm nút lệnh này (Click_Event) ta sẽ cho chạy thủ tục Nạp thêm 1 tập hợp có 100 mẫu tin tiếp theo 100 mẫu tin đã nạp.
Làm sao xác định là “100 mẫu tin tiếp theo”?
Tôi chỉ cần khai báo 1 biến cục bộ trong class module của form “frmContact” (chính là cái trang code ta mở phía sau form) để chỉ DanhbaId cuối cùng của tập hợp mẫu tin đã được nạp và đang hiện hữu. Vậy là ta sẽ xác định được giá trị của 2 tham số: FromId và ToId trong thủ tục “RetrieveDanhba” nêu trên.

Thế là ta đã thỏa mãn được yêu cầu chỉ nạp tập hợp mẫu tin trong phạm vi giới hạn cần dùng.

Sau đây là Link tải xuống file ứng dụng đã cập nhật theo bài này:
http://www.mediafire.com/?c9bi76gtn2dmjv9

Đến đây bài đã dài rồi, xin hẹn các Bạn bài sau ta sẽ bàn tiếp nhé.
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , bvchauthanh , quanghoasla , Minh Tiên
#17
Chào các Bạn,

Tối hôm qua có Bạn gọi hỏi tôi rằng: vậy muốn nạp trở lại 100 mẫu tin trước 100 mẫu tin đang hiện hữu thì làm sao?

Các Bạn thử làm như sau xem sao nhé:
1. Thêm 1 nút lệnh với caption "-100 Rec"
2. Viết thủ tục bẩy sự kiện click_event cho nút lệnh này, trong đó xác định 2 tham số FromId và ToId như sau:
+ ToId = (Id của mẫu tin cuối cùng trong tập hợp 100 mẫu tin đang hiện hữu) - 1
+ FromId = (Id của mẫu tin cuối cùng trong tập hợp 100 mẫu tin đang hiện hữu) - 100
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , bvchauthanh , Minh Tiên
#18
Chào các Bạn,

Về việc nạp dữ liệu nguồn cho form, chúng ta cũng cần chú ý đến việc nạp dữ liệu nguồn cho các ComboBox hoặc ListBox.
Khi nạp dữ liệu nguồn cho các ComboBox hoặc ListBox chúng ta cũng phải tuân thủ nguyên tắc chỉ nạp dữ liệu trong phạm vi giới hạn vừa đúng với nhu cầu khai thác xử liệu.
Sau đây tôi xin trình bày một trong những cách thức nạp dữ liệu nguồn cho ComboBox xác định tuân thủ nguyên tắc nêu trên. Cụ thể như sau:

Nhu cầu đặt ra là: trên form cần có 1 ComboBox dùng để liệt kê sẵn danh sách tên và địa chỉ khách có trong bảng dữ liệu “tblDanhsach”.
Thay vì ta cho nạp nguồn dữ liệu cho ComboBox này 1 lần ngay khi form được mở, ta sẽ cho lọc danh sách nguồn theo 1 điều kiện xác định.
Điều kiện lọc ở đây được ban hành bằng cách ta nhập thẳng 1 vài từ cần tìm trong tên của khách (có trong bảng danh sách), sau đó chương trình sẽ tự động nạp nguồn dữ liệu theo điều kiện lọc này. Làm như vậy ta sẽ hạn chế được khối lượng dữ liệu hữu ích cần nạp, đồng thwofi cũng làm cho việc hiện danh sách sổ xuống nhanh hơn.

Cách làm như sau:
- Giả định ta đặt tên ComboBox nói trên là “combo0
- Trong class module của form chứa ComboBox nêu trên, ta viết 1 thủ tục có nội dung như sau để thiết lập nguồn dữ liệu cho ComboBox “combo0”.
Thủ tục này có tham số “stFilter” sẽ là chuỗi ký tự lập thành điều kiện lọc do người sử dụng nhập vào tại ComboBox “combo0”.

Mã:
Private Sub SetComboRowSource(stFilter)
Dim sqlSt As String
Dim r As ADODB.Recordset

sqlSt = "SELECT ten, diachi, danhbaid FROM " & GetSchemaTable("tblDanhsach") & ".tblDanhsach"
sqlSt = sqlSt & " WHERE ten LIKE N'%" & stFilter & "%'"
sqlSt = sqlSt & " ORDER BY danhbaid"
Debug.Print sqlSt
Set r = ProcessRecordset(sqlSt)
Set Me.Combo0.Recordset = r
With Me.Combo0
    .BoundColumn = 1
    .ColumnCount = 3
    .ColumnWidths = "7 Cm;7 Cm;0"
End With
r.Close
Set r = Nothing
End Sub

Các Bạn lưu ý: thay vì cho nạp chuỗi nguồn dữ liệu cho property “RowSource” của ComboBox, tôi cho nạp thuộc tính “Recordset” cho ComboBox này. Tôi làm như vậy để cho gọn gàng thôi.

- Với ComboBox “combo0” ta viết thủ tục sự kiện Enter có nội dung như sau:

Mã:
Private Sub Combo0_Enter()
If Len(Me.Combo0) > 0 Then SetComboRowSource Me.Combo0
End Sub

Có Bạn nào có giải pháp khác xin trao đổi thêm nhé.
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , haquocquan , bvchauthanh , Minh Tiên
#19
Chào các Bạn,
Tôi vừa nhận được email của 1 Bạn hỏi về vấn đề nạp nguồn dữ liệu cho ComboBox mà chúng ta đã trao đổi ở #18. Bạn ấy hỏi:
"Tôi muốn cứ mỗi khi gõ vào 1 chuỗi thì ComboBox được lọc ngay theo chuỗi này thì phải làm sao?"

Ở đây ta cần cân nhắc xem việc lọc nguồn dữ liệu có cần thực hiện ngay tại thời điểm "cứ mỗi khi gõ vào" hay không?
Rõ ràng trong thực tế ta không cần đến mức tức thì "cứ mỗi khi gõ vào" như vậy. Nếu làm việc này tôi e rằng sẽ mất rất nhiều thời gian để ứng dụng nạp xong dữ liệu nguồn theo điều kiện lọc ta gõ vào.

Do đó, tôi đề nghị 1 giải pháp như sau: chỉ khi nào ta bấm phím lệnh cho hiện danh sách sổ xuống thì lúc ấy ứng dụng hãy cho nạp dữ liệu nguồn được lọc theo chuỗi ta đã nhập vào ComboBox.

Cách làm như sau:
1. Bỏ thủ tục đáp ứng sự kiện Enter của ComboBox như ta đã làm như đã trình bày trong bài trên (#18)
2. Viết thủ tục đáp ứng sự kiện KeyDown như sau, để mỗi khi ta bấm phím F4 hoặc tổ hợp phím (Alt+Mũi tên xuống) ứng dụng sẽ cho nạp dữ liệu nguồn được lọc theo chuỗi ta đã nhập vào ComboBox này.

Chúng ta đã biết: phím F4 hoặc tổ hợp phím (Alt+Mũi tên xuống) dùng để cho hiện danh sách sổ xuống của ComboBox

Mã:
Private Sub Combo0_KeyDown(KeyCode As Integer, Shift As Integer)
Dim stFilter
If KeyCode = vbKeyF4 Or (KeyCode = vbKeyDown And Shift = acAltMask) Then 'Bẩy phím F4 hoặc Alt+Mũi tên xuống
    stFilter = Me.Combo0.Text
    If Len(stFilter) > 0 Then
        SetComboRowSource stFilter
    End If
End If
End Sub

Các Bạn nào có giải pháp khác xin trao đổi thêm nhé.
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , haquocquan , bvchauthanh , maidinhdan , Minh Tiên
#20
Chào các Bạn,

Về việc kết nối với dữ liệu nguồn qua mạng máy tính tôi thấy cũng cần trao đổi thêm về việc tổ chức dữ liệu sao cho việc kết nối dữ liệu được thuận lợi và hiệu quả nhất.

Theo tôi thấy (có thể các Bạn sẽ thấy khác): Trong thực tế, không phải lúc nào chúng ta cũng cần lấy dữ liệu xuống bằng cách kết nối với dữ liệu nguồn đặt tại server; có những nguồn dữ liệu có tính ổn định nhất định (không bị thay đổi thường xuyên) ta có thể cho trích xuất với phạm vi giới hạn nhất định và cho lưu xuống máy client (máy khách cần kết nối vào server), sau đó ta sẽ cho nạp nguồn dữ liệu từ dữ liệu đã được trích xuất này. Làm như vậy ta vừa cải thiện được tốc độ truy xuất dữ liệu, vừa giảm được tải không cần thiết cho cả server và client.

Các Bạn thử xem xét tình huống sau đây nhé:
Với doanh nghiệp bán hàng trên phạm vi rộng, có ứng dụng chạy trên client kết nối đến dữ liệu nguồn ở server, ứng dụng này dành cho các nhân viên thị trường sử dụng trên các laptop để thực hiện nhiệm vụ "Tìm kiếm khách mua hàng và lập đơn đặt hàng theo bảng giá ấn định chung". Mỗi nhân viên thị trường đều được phân công phụ trách một phạm vi địa lý nhất định.

Như vậy, ta có thể cho trích xuất các nguồn dữ liệu sau lưu xuống máy client để ứng dụng client sử dụng trực tiếp, không cần phải lấy từ server thông qua kết nối qua mạng:
+ Danh sách khách hàng trong phạm vi địa lý đã phân công cho từng nhân viên;
+ Danh mục hàng hoá (có bảng giá) cũng trong giới hạn cần thiết.

Đồng thời với đó, ta sẽ có các thủ tục thích hợp để cho đồng bộ dữ liệu đang lưu tạm trên các máy Client với dữ liệu gốc trên server. Việc đồng bộ dữ liệu này sẽ được thực hiện tại thời điểm thích hợp (trong ngày hoặc trong tuần) hoặc khi có sự kiện thay đổi dữ liệu xảy ra (như đơn giá được người có thẩm quyền cập nhật mới, ...).

Các Bạn có thấy điều gì không ổn trong đề nghị trên của tôi không? Xin vui lòng góp ý trao đổi thêm.
Chữ ký của lehongduc Lê Hồng Đức
Số ĐT: 0913.941.144
Email: lhongduc@gmail.com, lehongduc@ymail.com
Website: http://quantribanhang.vn
Reply
Những người đã cảm ơn Noname , haquocquan , bvchauthanh , quanghoasla , maidinhdan , Minh Tiên , hmhieu


Có thể liên quan đến chủ đề
Chủ đề: Tác giả Trả lời: Xem: Bài mới nhất
Question [Help] Link tất các table trong một file.mdb bằng VBA MinhnHang 8 187 4 Giờ trước
Bài mới nhất: MinhnHang
  [Thủ Thuật] Tìm số thứ tự bị thiếu trong dãy toanle 8 204 07-12-16, 02:25 PM
Bài mới nhất: toanle
  Sựa khác nhau giữa Module và Class Module, phạm vi áp dụng của từng loại. MinhnHang 6 304 29-11-16, 09:11 PM
Bài mới nhất: ongke0711
  Tránh xung đột dữ liệu trong access quocdung9999 16 1,692 23-11-16, 11:13 AM
Bài mới nhất: quocdung9999
  [Hỏi] Kết nối nhiều lần hay kết nối 1 lần trong ADO ưu điểm hơn Minh Tiên 1 123 10-11-16, 10:41 AM
Bài mới nhất: maidinhdan

Chuyển nhanh:


User(s) browsing this thread: 1 Guest(s)
Diễn Đàn Thơ Văn Thi Ẩm Lâu|Nhà Hàng Sông Thơ