Cùng mổ xẻ chương trình mẫu VDP

Ðề: Cùng mổ xẻ chương trình mẫu VDP

Đối với cách thiết kế của tôi thì tôi sẽ có một table xác lập quyền cho user. Mỗi dòng bao gồm username, formname, available. Nếu available = True thì cho phép user đó truy cập form đó. Nếu nạp nó vào menu chẳng hạn thì cũng dễ dàng thôi.

Cũng còn vấn đề nữa là: menu có thể ở cấp độ ứng dụng chứ không chỉ ở cấp độ form.
Application.commandbars("tenxxx")...
Do trong các ví dụ ở trên ta cho nó hiện lên hoặc cất đi trong các sự kiện form load, close .... đó chỉ là ví dụ thôi.


Rất hay, tập hợp các bài viết này tạo thành 1 cuốn sách có giá trị đấy bác. Hiện nay em đọc hầu hết các giáo trình access thì ít đề cập đến việc tạo menu bằng code mà chỉ có dùng Macro. Trong khi đó để thay đổi nội dung nhanh chóng thì dùng code (nhất là khi cho nó vào table để truy vấn) thì nhanh và hiệu quả hơn nhiều
Và vì thế bầu trời chỉ bằng nắp vung !!!:smilielol5:

Đọc giáo trình Access chưa thấy thì đọc giáo trình ...Excel, Word ...
Hoặc là nhấn F1.
Mấy cái code đó đâu phải do tôi chế ra đâu mà bảo là tìm hổng thấy.
Vậy đó. Nếu có ai đó ghi trong đơn xin việc là "thành thạo Access, Excel" thì chớ vội tin.


Tip: Mấy cái code này bạn có dùng để tạo menu trong Excel. Tất nhiên đối tượng có hơi khác tí chút.

Bac muontennguoi oi, cái shortcutbar của bác làm thế nào để cho 1 nút lệnh do mình địnhnghĩa: Mấy cái dòng như thế này Set cbc = Cmb.Controls.Add(msoControlButton, CommandBars("Edit").Controls("Paste").Id) là lấy ID sẵn có của access, em muốn tạo thêm 1 nút cho riêng mình

Thì đừng khai báo ID trong lệnh Add().
ID chỉ dành riêng cho button built-in.
Các button tự tạo đều có chung id = 1.
Cách khai báo button tự tạo thì xem lại phần trước.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Và vì thế bầu trời chỉ bằng nắp vung !!!:smilielol5: .
Bằng vung vẫn còn hơi to, theo thuyết mới cả vũ trụ mới chỉ bằng 1 đồng xu thôi.:hysterical:

Ah, còn cái vụ chỉ cho hiện 1 số dòng cuối cùng trong 1 subform có nhiều bản ghi thì thế nào bác nhỉ
-----------------------------------------------------------------------------------------
Cách một là sẽ có một table chứa các thông số về form được sử dụng trong chương trình (tạm gọi là table form mẫu). Nó chứa: ID của form, Caption tức là cái sẽ hiển thị trên một form điều khiển như là menu command vậy, và cái FormName.

Hình như cái VDP em up lên cũng xử lý theo hướng này, tuy nhiên em vẫn chưa hiểu rõ chức năng của nó . Để ngâm cứu thêm vậy.
 
Sửa lần cuối:
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Có 1 vấn đề nhờ các bác giải thích dùm
Em có 1 module sau:
Public Function ketnoi(sql) As ADODB.Recordset

Dim cn As New ADODB.Connection
connStr = "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=C:-/Vidu\qlns.mdb;"
'On Error GoTo err_Connection
With cn
.ConnectionString = connStr
.Open
End With
Dim rs As New ADODB.Recordset
With rs
.ActiveConnection = cn
.LockType = adLockOptimistic 'tùy
.CursorLocation = adUseClient
.Open (sql)
End With
Set ketnoi = rs

end_ketnoi:
Exit Function
'err_Connection:
'MsgBox Err.Description
Set ketnoi = Nothing
Resume end_ketnoi
End Function

và 1 form trống. Thuộc tính khi form_load được viết như sau:
Private Sub Form_Load()
sql = "Select tenmenu,giatri,icon,lenh,quyen,khoa from tbl_menu order by ID"
ketnoi(sql).MoveFirst
Do While Not ketnoi(sql).EOF
msgbox ketnoi(sql).fields(0)
ketnoi(sql).MoveNext
Loop
End Sub


Khi chạy msgbox chỉ luôn lấy giá trị của dòng đầu tiên mặc dù đã cho nó movenext. Nghĩ mãi mà chưa biết nguyên nhân tại sao cả
-----------------------------------
Cuối cùng cũng xử lý được, phải khai báo thêm
dim rs as recordset
set rs=ketnoi(sql)
nhưng vẫn chưa hiểu tại sao phải như vậy vì rs và ketnoi(sql) đều là recordset. Các bác cho ý kiến
 
Sửa lần cuối:
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Phải phân biệt danh từ và động từ chứ.
Để như vậy chạy một hồi mà máy của bạn không bốc khói mới là lạ.

Cứ mỗi vòng lặp bạn lại gọi:
msgbox ketnoi(sql).fields(0)

NHư vậy nó phải thực hiện kết nối lại và thực hiện lại query ...
Do phải thực hiện lại query nên msgbox chỉ luôn nhận được dòng đầu tiên.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Bác muontennguoi viết thêm các bài khác nữa đi. Bác viết có chú thích nên rất dễ hiểu. Em nghĩ có 1 số vấn đề cần bác viết cho anh em học hỏi
1. Hiện thị, cập nhật, xóa dữ liệu trên lưới
2. Menu dạng cây
3. Back up dữ liệu
4. Mã hóa dữ liệu
5. Chạy access khi máy không cài access
PS: Em vừa tạo 1 CSDL và không dùng tới relationship. Việc cập nhật, truy vấn thì không có vấn đề gì. Nhưng khi xóa dữ liệu thì :
khi xóa 1 bản ghi tại table1 thì các trường dữ liệu tại table2 (tabl1 và table2 quan hệ 1-n) vẫn giữ nguyên như thế sẽ không đảm bảo cho dữ liệu. Do đó em nghĩ có 2 cách
1. Vẫn phải tạo 1 relationship cho chúng
2. Lần lượt thao tác xóa dữ liệu trên cả 2 trường dữ liệu (cái này có vẻ phức tạp hơn )
Bác xử lý nhiều rồi cho em 1 góp ý
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Sau khi form gọi kết nối thành công thì lệnh ngắt kết nối viết thế nào bây giờ hả bác
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Sau khi form gọi kết nối thành công thì lệnh ngắt kết nối viết thế nào bây giờ hả bác
set cn = nothing
Trong đoạn code phía trên của behattieu tách kết nối riêng ra như vậy là không hợp lý.


Bác muontennguoi viết thêm các bài khác nữa đi. Bác viết có chú thích nên rất dễ hiểu. Em nghĩ có 1 số vấn đề cần bác viết cho anh em học hỏi
1. Hiện thị, cập nhật, xóa dữ liệu trên lưới
2. Menu dạng cây
3. Back up dữ liệu
4. Mã hóa dữ liệu
5. Chạy access khi máy không cài access
PS: Em vừa tạo 1 CSDL và không dùng tới relationship. Việc cập nhật, truy vấn thì không có vấn đề gì. Nhưng khi xóa dữ liệu thì :
khi xóa 1 bản ghi tại table1 thì các trường dữ liệu tại table2 (tabl1 và table2 quan hệ 1-n) vẫn giữ nguyên như thế sẽ không đảm bảo cho dữ liệu. Do đó em nghĩ có 2 cách
1. Vẫn phải tạo 1 relationship cho chúng
2. Lần lượt thao tác xóa dữ liệu trên cả 2 trường dữ liệu (cái này có vẻ phức tạp hơn )
Bác xử lý nhiều rồi cho em 1 góp ý

Một vấn đề nhỏ như là làm menu mà bạn còn lười đọc help nên tôi phải viết ra bằng tiếng Việt.
Chỉ nội cái menu cũng phải hơn 10 bài mới gọi là tạm sơ sơ được 1/2 đường.
Hỏi 1 hơi 5-6 vấn đề thì ai mà làm cho nổi.
Lực lượng IT4DKT hiện nay vẫn còn mỏng.
========
PS: relationship là cái gì?
Thực ra thì đằng sau màn hình máy nó vẫn phải làm cái công việc xoá bảng1 rồi nhảy sang xoá tiếp bảng 2, bảng 3 ...

Trong khi nếu ta tự làm có khi lại thông minh hơn nó (Access).:hypo:
Bởi vì dù sao đi nữa Access cũng chỉ thiết kế để thực hiện trên bình diện chung, mọi người cơ bản là xài relationship được.
Nếu kết cấu đối tượng phức tạp hơn thì vẫn phải do con người quyết định. Máy không phải là thánh.

Ví dụ: Sau khi cập nhật xong (sau 1 chầu làm việc) phát 1 lệnh DELETE ...WHERE ... là OK.
Nếu quên không có lệnh đó thì khi truy xuất dữ liệu cũng không bao giờ ảnh hưởng vì nếu:
SELECT ... FROM table1, table2 WHERE table1.tk = table2.tk
như vậy dù dữ liệu vẫn còn nằm trong table2 thì nó cũng không được tính đến.
Vấn đề là khi viết code truy xuất dữ liệu luôn phải tính đến loại trừ các record không hợp chuẩn vẫn còn tồn tại, vì lý do nào đó.


Kiểm soát toàn vẹn dữ liệu là chuyện thườgn xuyên phải làm.
DN phải có người chịu trách nhiệm admin mà quản lý, bảo vệ số liệu quý giá của mình.
Cho dù có sử dụng relationship của Access hay SQL thi cũng phải thường xuyên truy vấn có rẽcord nào không hợp lệ hay không. Đừng chủ quan.

Hơn nữa nếu connect trên mạng kiểu internet thì không có thông báo lỗi nào được trả lại.
Rốt cuộc ta cũng phải xử lý chuyện đó.

Nếu người dùng cuối không biết Access mà chương trình của ta (chạy mạng LAN hoặc máy đơn) trả lại chình ình cái thông báo bằng tiếng ANH thì họ cũng réo ta đến mà thôi.
Tính đi tính lại rồi thì cũng phải tự mình chỉnh sửa thôi. Chứ ai vô đây.

Phải có 1 đoạn code làm công cụ kiểm tra tính hợp lệ của dữ liệu.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Nói tiếp lời của bác mượn một chút về relationship.
Về cái cascade update thì không vấn đề, nhưng cái cascade delete thì cần chú ý.
Cái cascade delete sẽ khiến cho khi bạn xóa một record trong table chiều 1 thì những record quan hệ tương ứng ở table chiều nhiều sẽ tự động xóa theo.
Ở đa số thì cái này OK, nhưng bạn thử hình dung xem, có một khách hàng đã làm ăn với bạn một thời gian, sau đó thì thôi. Đến một lúc nào đó, xếp bạn hay chính bản thân bạn yêu cầu "thanh lọc". Nếu bạn delete thông tin một khách hàng mà quan hệ có ràng buộc cascade delete với phiếu nhập hoặc phiếu xuất thì điều gì xảy ra, chắc bạn cũng hiểu.
Và nữa khi xóa xong rồi, xếp bạn hay bạn muốn lập báo cáo nhập xuất chẳng hạn mà thời khoảng báo cáo lại có dính đến khách hàng đã xóa. Vậy báo cáo của bạn còn đúng không vậy ta?
Thực tế, ít ai cho xóa tự động bằng ràng buộc cascade đâu bạn.
Chinh chiến nhiều sẽ thấy nhiều điều kỳ ... cục. :confuse1:
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Lúc nào rảnh các bác làm 1 sample về kết nối ADO giúp bọn em nhé.
Em vẫn đang loay hoay với mấy cái nút lệnh truyền thống (thêm, xóa, sửa) mà không sử dụng theo mặc định của access. Tuy nhiên mỗi lần thao tác lại phải khai báo lại toàn bộ kết nối dạng:
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim sql As String

Set cnn = New ADODB.Connection
mydb = "D:-/QNS\data.mdb"
strCnn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & mydb
cnn.Open strCnn

sql = "delete * from tbl_hosocanhan WHERE (((tbl_hosocanhan.MLD)='" & Me.MLD & "'));"
Set rst = New ADODB.Recordset
rst.ActiveConnection = cnn
rst.CursorLocation = adUseClient
rst.Open sql, , adOpenStatic, adLockOptimistic

Trong khi đó em biết có phương thức chỉ cần gọi
rst.Delele
là OK rồi.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Lúc nào rảnh các bác làm 1 sample về kết nối ADO giúp bọn em nhé.
Em vẫn đang loay hoay với mấy cái nút lệnh truyền thống (thêm, xóa, sửa) mà không sử dụng theo mặc định của access. Tuy nhiên mỗi lần thao tác lại phải khai báo lại toàn bộ kết nối dạng:
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim sql As String

Set cnn = New ADODB.Connection
mydb = "D:-/QNS\data.mdb"
strCnn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & mydb
cnn.Open strCnn

sql = "delete * from tbl_hosocanhan WHERE (((tbl_hosocanhan.MLD)='" & Me.MLD & "'));"
Set rst = New ADODB.Recordset
rst.ActiveConnection = cnn
rst.CursorLocation = adUseClient
rst.Open sql, , adOpenStatic, adLockOptimistic

Trong khi đó em biết có phương thức chỉ cần gọi
rst.Delele
là OK rồi.

rst.Delete tất nhiên là có, và như vậy bạn cũng có thể dùng.
Gọi phương thức đầy đủ (với ADODB.recordset):
rs.Delete affectedRecords

Trong đó, affectedRecords là một enum chỉ định có bao nhiêu record sẽ bị ảnh hưởng bởi lệnh. Gồm các enum sau:
adAffectAll: nếu không có filter, toàn bộ record sẽ bị delete.
adAffectAllChapters: sẽ có ảnh hưởng đến các recordset liên quan.
adAffectCurrent: chỉ ảnh hưởng với record hiện hành. Mặc định.
adAffectGroup: chỉ những record được filter mới bị ảnh hưởng.

Tùy theo mong muốn thì bạn chọn những enum trên.

Với DAO.recordset thì chỉ đơn thuần là record hiện hành mà thôi.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Nếu chỉ liên kết với 1 table thì đơn giản nhưng hiện tại em đang lăn tăn khi có nhiều form kết nối đến nhiều table. Không biết gọi kết nối và xử lý recordset thế nào cho tiện.
1. Mỗi form khai báo 1 kết nối và xử lý trên form đó
2. Khai báo 1 public kết nối rồi gọi kết nối đó mỗi khi cần lấy dữ liệu<==cái này đang khó nghĩ đây các bác ạ.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Nếu chỉ liên kết với 1 table thì đơn giản nhưng hiện tại em đang lăn tăn khi có nhiều form kết nối đến nhiều table. Không biết gọi kết nối và xử lý recordset thế nào cho tiện.
1. Mỗi form khai báo 1 kết nối và xử lý trên form đó
2. Khai báo 1 public kết nối rồi gọi kết nối đó mỗi khi cần lấy dữ liệu<==cái này đang khó nghĩ đây các bác ạ.

Khai báo public hay private không có gì phải lăn tăn.
Public cũng được, nhưng nhớ là khi xử lý xong, nên tạm đóng nó lại: connection.Close.
Khi nào muốn kết nối lại thì:
If connection.State = adState.Closed Then
connection.Open
End If
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Em gặp một vấn đề sau. Khi dùng câu lệnh:
ModADO.DeleteDB "MLD", me.MLD
thì nó luôn xóa giá trị đầu tiên mặc dù Me.MLD có giá trị >1.
Module xóa dữ liệu như sau:
Public Function DeleteDB(DeleteField As String, DeleteValue As String)
rst.Delete adAffectCurrent
rst.UpdateBatch
End Function
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Em gặp một vấn đề sau. Khi dùng câu lệnh:
ModADO.DeleteDB "MLD", me.MLD
thì nó luôn xóa giá trị đầu tiên mặc dù Me.MLD có giá trị >1.
Module xóa dữ liệu như sau:
Public Function DeleteDB(DeleteField As String, DeleteValue As String)
rst.Delete adAffectCurrent
rst.UpdateBatch
End Function

Thấy cái câu có màu đỏ không vậy?
adAffectCurrent là chỉ có hiệu lực cho record hiện hành mà thôi. Khi mở recordset ra, nếu có record thì nó đứng ở record đầu tiên. Hiển nhiên là chỉ xóa record đầu chứ còn gì?

Sao không chịu khó đọc cái bài đã đăng cũng trong topic này ??? Bó tay.
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Em chỉ không hiểu chỗ này:
ModADO.DeleteDB "MLD", me.MLD
Vì em nghĩ nó đã so sánh dữ liệu trong recordset với Me.MLD. Nếu phù hợp thì nó xoá, còn khôngphù hợp thì nó bỏ qua.
Tuy nhiên em cũng đã giải quyết bằng cách dùng lệnh Movenext đến Me.MLD rồi mới thực hiện lệnh xóa như vậy có cần thiết phải so sánh "MLD" với Me.MLD không? vì nó đã luôn xóa bản ghi hiện tại
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Em chỉ không hiểu chỗ này:
ModADO.DeleteDB "MLD", me.MLD
Vì em nghĩ nó đã so sánh dữ liệu trong recordset với Me.MLD. Nếu phù hợp thì nó xoá, còn khôngphù hợp thì nó bỏ qua.
Tuy nhiên em cũng đã giải quyết bằng cách dùng lệnh Movenext đến Me.MLD rồi mới thực hiện lệnh xóa như vậy có cần thiết phải so sánh "MLD" với Me.MLD không? vì nó đã luôn xóa bản ghi hiện tại

Cái đoạn của bạn không có có cái việc duyệt recordset để xóa.

Public Function DeleteDB(DeleteField As String, DeleteValue As String)
rst.MoveFirst
Do While not rst.EOF
rst.Find deleteField & "=N'" & deleteValue & "'"
If Not rst.EOF Then
rst.Delete adAffectCurrent
EndIf
rst.MoveNext
Loop
rst.UpdateBatch
End Function
 
Ðề: Cùng mổ xẻ chương trình mẫu VDP

Nếu thêm cái này
rst.Find deleteField & "=N'" & deleteValue & "'"
End Function

thì nó lại luôn xoá với giá trị của các trường dữ liệu mặc định . Trong khi đó function deleteDB dùng để xoá cho mọi rst với các nguồn SQL khác nhau ( có thể lúc này xoá trường A, lúc khác lại xoá trường B.
Do đó khi thực hiện lệnh xoá em cho nó dịch chuyển đến bản ghi có giá trị lọc theo các trường dữ liệu mình muốn, sau đó gọi function deleteDB
 

CẨM NANG KẾ TOÁN TRƯỞNG


Liên hệ: 090.6969.247

KÊNH YOUTUBE DKT

Cách làm file Excel quản lý lãi vay

Đăng ký kênh nhé cả nhà

SÁCH QUYẾT TOÁN THUẾ


Liên hệ: 090.6969.247

Top