uronmapu > 20-06-12, 01:39 PM
buitheduy > 25-10-12, 03:54 PM
(23-05-12, 04:29 PM)n2kp Đã viết: Xin chào cả nhà.Tôi đã làm theo hương dẫn của bạn nhưng khi chay thì chương trình báo lỗi: user-defined type not defined.
Tôi có viết một chương trình Access quản lý công việc trong phòng tại cơ quan. Tôi dùng phương pháp BackEnd và FrontEnd để chia sẻ dữ liệu trong mạng Lan, tổng số user khoảng 10 người. Chương trình chạy tốt và hiệu quả. Tuy nhiên có một vấn đề mà lâu nay tôi chưa tìm ra giải pháp tối ưu là làm sao biết được ai đã sửa dữ liệu trên form ngày giờ nào, và sửa như thế nào.
Tôi đã tìm kiếm nhiều giải pháp trên diễn đàn và đã áp dụng, tuy nhiên code rất dài, phức tạp, khó quản lý. Bởi tổng số record trong CSDL hơn 7000 records cùng với 10 users cùng làm việc hàng ngày, quản lý tốt CSDL là nhiệm vụ hàng đầu, hơn nữa trong phòng không phải ai cũng hiểu rõ vấn đề bảo vệ CSDL là quan trọng như thế nào.
Và thật không ngờ, không phải giải pháp cao siêu gì cả, rất đơn giản mà thật hiệu quả. Giờ đây, mỗi sáng tôi chỉ mở form theo dõi là có thể biết ai đã làm gì hôm qua, dữ liệu nào đã chỉnh sửa, giá trị cũ sang giá trị mới ra sao, không phải nhức đầu khi phải phân quyền cho từng user. Bây giờ ai cũng có thể chỉnh sửa dữ liệu và có trách nhiệm với việc thay đổi của mình.
Nói hơi dông dài để các bạn có thể hiểu rõ hơn vấn đề. Hôm nay tôi sẽ chia sẻ giải pháp của tôi với các bạn với mục đích là cùng nhau học hỏi. Biết đâu đây chưa phải là giải pháp tốt nhất. Rất mong sự chia sẻ từ diễn đàn.
I. MÔ TẢ CHƯƠNG TRÌNH
Khi mở chương trình sẽ có Form Đăng nhập như sau
Sau khi đăng nhập đúng username và password, click button Đăng nhập sẽ mở ra Form Customers (lấy mẫu từ NorthWind Database của MS Office 2003)
Từ đây, bạn có thể sửa bất kỳ record nào, bất kỳ control nào trên form. Sau khi cập nhật dữ liệu xong, bạn đóng Form, thế thì xong.
Thế làm sao bạn có thể biết user nào đã cập nhật dữ liệu, cập nhật khi nào. Đây mới chính là vấn đề cần giải quyết. Chúng ta sẽ có một table tblLuuVetChuongTrinh ghi lại tất cả các hoạt động của user trên form này. Nào bạn hãy mở table tblLuuVetChuongTrinh, chúng ta sẽ có gì.
Giờ đây ta đã biết user nào sửa control nào, giá trị cũ qua giá trị mới, ngày giờ cụ thể. Bạn chỉ cần tạo một form lọc những giá trị cần biết để quản lý tốt hơn CSDL của mình.
II. GIẢI QUYẾT VẤN ĐỀ
Trong CSDL mẫu này, bạn hãy import 1table Customers và 1 form Customers từ NorthWind Database, bỏ đi tất cả code trong AfterUpdate của từng Control và Form của Customers Form nguyên gốc.
1. Tạo table tblUsers có cấu trúc như sau:
2. Nhập tên user và password của từng user
3. Tạo table tblLuuVetChuongTrinh có cấu trúc như sau:
4. Tạo 5 biến toàn cục (Global) trong standard module
Option Compare Database
Public GvarUserName As String
Public varOldValue As String
Public varNewValue As String
Public varControlName As String
Public varFormName As String
Các biến toàn cục này có ý nghĩa thế nào chắc không cần giải thích các bạn nhỉ
Khi form Đăng nhập mở lên, user chọn username từ combo box và gõ password, sau đó click button Đăng nhập, nếu chọn đúng tất cả sẽ mở form Customers, đồng thời sẽ gán biến toàn cục GvarUsernName = UserName.
Đây là đoạn code kiểm tra khi click vào button đăng nhập (OnClick)
Private Sub cmdDangNhap_Click()
Dim varPassword As String
' Doan code khong cho Control cbUserName trong hay rong
If IsNull(Me.cbUserName) Or Me.cbUserName = "" Then
MsgBox "Please select Username!", vbCritical, "Require Data"
Me.cbUserName.SetFocus
Exit Sub
End If
' Doan code khong cho Control txtPassword trong hay rong
If IsNull(Me.txtPassword) Or Me.txtPassword = "" Then
MsgBox "Please enter Password!", vbCritical, "Require Data"
Me.txtPassword.SetFocus
Exit Sub
End If
varPassword = DLookup("Password", "tblUser", "Username ='" & Me.cbUserName & "'")
If Me.txtPassword = varPassword Then
GvarUserName = Me.cbUserName
DoCmd.Close acForm, Me.Name
DoCmd.OpenForm "Customers"
Else
MsgBox "Incorect Password. Please contact the Administrator.", vbCritical, "Cannot access the Database"
Me.txtPassword.SetFocus
Exit Sub
End If
End Sub
Sau khi form Customers mở lên, user sửa đổi dữ liệu thì sẽ có một hàm lưu lại các thay đổi đó, đồng thời ghi các thay đổi đó vào table tblLuuVetChuongTrinh. Chúng ta đã có 5 biến toàn cục (global) đã định nghĩa ở trên, vấn đề là chúng ta sẽ gán giá trị cho các biến như thế nào. Ở đây với sự kiện AfterUpdate cho từng control trên form chúng ta sẽ gọi một Function có tên GoiHamLuuVetChuongTrinh. Đây chính là cái quan trọng nhất của chương trình, không cao siêu, không phức tạp, cực kỳ đơn giản. Function GoiHamLuuVetChuongTrinh được tôi viết như sau:
Function GoiHamLuuVetChuongTrinh()
If IsNull(Screen.ActiveControl.OldValue) Then
varOldValue = ""
Else
varOldValue = Screen.ActiveControl.OldValue
End If
If IsNull(Screen.ActiveControl.Value) Then
varNewValue = ""
Else
varNewValue = Screen.ActiveControl.Value
End If
varControlName = Screen.ActiveControl.Name
varFormName = Screen.ActiveForm.Name
Call CapNhatLuuVet(GvarUserName, varOldValue, varNewValue, varControlName, varFormName)
End Function
Hàm này sẽ gán từng giá trị cho các biến toàn cục ở trên, ngữ pháp câu lệnh đơn giản, tuy nhiên theo tôi kỹ thuật dùng Screen.ActiveControl đã biến những việc phức tạp trở nên cực kỳ đơn giản. Kỹ thuật này không cần biết Control đó tên gì, giá trị bao nhiêu mà chỉ đơn giản là Screen.ActiveControl.
Function CapNhatLuuVet sẽ add các biến toàn cục vào tblLuuVetChuongTrinh.
Function CapNhatLuuVet(fUserName, fOldValue, fNewValue, fControlName, fFormName)
Dim db As Database
Dim rst As Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("tblLuuVetChuongTrinh")
rst.AddNew
rst!TenUser = fUserName
rst!GiaTriCu = fOldValue
rst!GiatriMoi = fNewValue
rst!TenControl = fControlName
rst!TenForm = fFormName
rst!NgayCapNhat = Date
rst!GioCapNhat = Time()
rst.Update
rst.Close
Set rst = Nothing
Set db = Nothing
End Function
Sau khi đã có 2 function quan trọng trên, bạn vào từng control một trên form Customers chon sự kiện AfterUpdate và gõ (hoặc copy) chỉ một dòng lệnh sau:
Call GoiHamLuuVetChuongTrinh
Thế là xong, riêng tôi đã cất đi gánh nặng khi phải suy nghĩ về cách phân quyền cho từng user (ai được sửa cái gì, ai không được sửa cái gì, làm sao theo dõi . . .) khi áp dụng kỹ thuật này. Mỗi người đều có một phương pháp riêng để giải quyết các vấn đề trong công việc, sao cho ĐƠN GIẢN, NHANH CHÓNG, HIỆU QUẢ. Rất mong những ý kiến đóng góp của tất cả các bạn ở diễn đàn thuthuataccess.com và hy vọng các bạn có một giải pháp tốt hơn cho vấn đề này.
ppdung.public > 21-03-14, 03:13 AM
(31-05-12, 02:53 PM)n2kp Đã viết:(29-05-12, 05:40 PM)connguoi123 Đã viết: Trong trường hợp mình muốn trong bảng tblLuuvetchuongtrinh có nêu rõ được cả bản ghi nào được user tác động kô ( để biết người sử dụng tác động vào record nào - Ví dụ số hóa đơn nào chẳng hạn )? Vậy phải làm như nào, mong các bạn chỉ giáo thêm, tôi thấy cái này hay và tiện lợi quá. Cám ơn rất nhiều.
Chào bạn,
Bạn có thể thêm một trường (vd:IDHoadon) vào tblLuuvetchuong trình và trong Function CapNhatLuuVet bạn thêm một tham số IDhoadon, lúc đó Function CapNhatLuuVet chi tiết sẽ như thế này:
Function CapNhatLuuVet(IDhoadon, fUserName, fOldValue, fNewValue, fControlName, fFormName)
Dim db As Database
Dim rst As Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("tblLuuVetChuongTrinh")
rst.AddNew
rst!IDhoadon = IDhoadon
rst!TenUser = fUserName
rst!GiaTriCu = fOldValue
rst!GiatriMoi = fNewValue
rst!TenControl = fControlName
rst!TenForm = fFormName
rst!NgayCapNhat = Date
rst!GioCapNhat = Time()
rst.Update
rst.Close
Set rst = Nothing
Set db = Nothing
End Function
Thân chào.
winer531 > 02-04-14, 05:42 PM
(31-05-12, 02:53 PM)n2kp Đã viết:(29-05-12, 05:40 PM)connguoi123 Đã viết: Trong trường hợp mình muốn trong bảng tblLuuvetchuongtrinh có nêu rõ được cả bản ghi nào được user tác động kô ( để biết người sử dụng tác động vào record nào - Ví dụ số hóa đơn nào chẳng hạn )? Vậy phải làm như nào, mong các bạn chỉ giáo thêm, tôi thấy cái này hay và tiện lợi quá. Cám ơn rất nhiều.
Chào bạn,
Bạn có thể thêm một trường (vd:IDHoadon) vào tblLuuvetchuong trình và trong Function CapNhatLuuVet bạn thêm một tham số IDhoadon, lúc đó Function CapNhatLuuVet chi tiết sẽ như thế này:
Function CapNhatLuuVet(IDhoadon, fUserName, fOldValue, fNewValue, fControlName, fFormName)
Dim db As Database
Dim rst As Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("tblLuuVetChuongTrinh")
rst.AddNew
rst!IDhoadon = IDhoadon
rst!TenUser = fUserName
rst!GiaTriCu = fOldValue
rst!GiatriMoi = fNewValue
rst!TenControl = fControlName
rst!TenForm = fFormName
rst!NgayCapNhat = Date
rst!GioCapNhat = Time()
rst.Update
rst.Close
Set rst = Nothing
Set db = Nothing
End Function
Thân chào.
changkhoonline77 > 19-06-14, 09:09 AM
btamsgn > 14-07-14, 01:16 PM
changkhoonline77 > 30-09-14, 07:14 PM
(14-07-14, 01:16 PM)btamsgn Đã viết: Chào các bạn,Không biết bạn làm được chưa nhưng file download bị lỗi rồi.
Mình đã làm theo hướng dẫn trên của n2kp
Tuy nhiên chương trình không update giá trị cũ và mới.
Không biết mình đã làm sai ở khâu nào.
Các bạn xem file đính kèm và sửa giúp mình.
http://www.mediafire.com/download/1cp9eg...a/test.zip
Thanks,
Tâm
mrsiro > 10-12-14, 04:29 PM
kiengxuong > 22-06-15, 06:12 PM
Noname > 23-06-15, 10:12 AM
(22-06-15, 06:12 PM)kiengxuong Đã viết: Xin chào mọi người mình làm giống bạn đã chạy ok trên file acc bình thường nhưng khi mình cho table tblLuuVetChuongTrinh lên sql rồi mình link table tới sql nó báo lỗi ở phần code
Function CapNhatLuuVet(fUserName, fOldValue, fNewValue, fControlName, fFormName)
Dim DB As DAO.Database
Dim rst As DAO.Recordset
Set DB = CurrentDb
Set rst = DB.OpenRecordset("tblLuuVetChuongTrinh", dbOpenSnapshot)
rst.AddNew báo lỗi
rst!TenUser = fUserName
rst!GiaTriCu = fOldValue
rst!GiatriMoi = fNewValue
rst!TenControl = fControlName
rst!TenForm = fFormName
rst!NgayCapNhat = Date
rst!GioCapNhat = time()
rst.Update
rst.Close
Set rst = Nothing
Set DB = Nothing
End Function
mong bạn chỉnh sửa giúp mình Cảm ơn bạn rất nhiều
khongventoan@gmail.com