Major0418 > 11-09-21, 10:56 PM
paulsteigel > 12-09-21, 10:10 AM
(11-09-21, 10:56 PM)Major0418 Đã viết: Chào các bạn, mình đang thiết kế một Database đơn giản như sau:
- Table1, gồm các Field: ID (để Number và Index No Duplicate) và NoiDung
- Form1, lấy source từ Table1
Mình đặt Event cho Form1 là On Open -> Go To Record -> New để khi mở Form1 sẽ vào luôn phần nhập Record mới. Đặt Default Value =DMax("ID","Table1")+1 để tự nhảy số ID mỗi khi mở Form1.
Đồng thời đặt thêm On Open -> Save Record. Mục đích là khi mở Form1 lên sẽ có ngay một Record mới trong Table1, vì Table1 sẽ để linked cho người máy khác cùng nhập. Mình để thêm Open Form là Save Record để khi mở Form1 sẽ gán ngay một số ID cho người đang nhập, nhằm tránh trường hợp người thứ nhất đang nhập chưa lưu thì người thứ hai vào nhập sẽ bị trùng giá trị ID.
Tuy nhiên, khi mở Form1 thì vẫn không tự lưu Record, vì khi mở Table1 ra vẫn chưa có record mới, mà phải nhập cả NoiDung và bấm save thủ công thì trong Table1 mới ghi nhận có Record mới.
Vì mình mới biết đến Access được 3 ngày, chưa biết code và VBA nên mong các bạn giải thích và hướng dẫn. Cảm ơn các bạn.
Mình xin gửi kèm File: https://drive.google.com/file/d/1rjeZC8S...gWErIYgnzo
Major0418 > 12-09-21, 11:04 AM
(12-09-21, 10:10 AM)paulsteigel Đã viết:(11-09-21, 10:56 PM)Major0418 Đã viết: Chào các bạn, mình đang thiết kế một Database đơn giản như sau:
- Table1, gồm các Field: ID (để Number và Index No Duplicate) và NoiDung
- Form1, lấy source từ Table1
Mình đặt Event cho Form1 là On Open -> Go To Record -> New để khi mở Form1 sẽ vào luôn phần nhập Record mới. Đặt Default Value =DMax("ID","Table1")+1 để tự nhảy số ID mỗi khi mở Form1.
Đồng thời đặt thêm On Open -> Save Record. Mục đích là khi mở Form1 lên sẽ có ngay một Record mới trong Table1, vì Table1 sẽ để linked cho người máy khác cùng nhập. Mình để thêm Open Form là Save Record để khi mở Form1 sẽ gán ngay một số ID cho người đang nhập, nhằm tránh trường hợp người thứ nhất đang nhập chưa lưu thì người thứ hai vào nhập sẽ bị trùng giá trị ID.
Tuy nhiên, khi mở Form1 thì vẫn không tự lưu Record, vì khi mở Table1 ra vẫn chưa có record mới, mà phải nhập cả NoiDung và bấm save thủ công thì trong Table1 mới ghi nhận có Record mới.
Vì mình mới biết đến Access được 3 ngày, chưa biết code và VBA nên mong các bạn giải thích và hướng dẫn. Cảm ơn các bạn.
Mình xin gửi kèm File: https://drive.google.com/file/d/1rjeZC8S...gWErIYgnzo
Trong môi trường Access, nếu bạn muốn nhiều người dùng cùng làm việc thì bạn cần tách ứng dụng của bạn thành 2 phần:
1. Backend để lưu trữ dữ liệu, đặt trên một thư mục chia sẻ (share) trong mạng: giả sửa đường dẫn đến backend là \\server\data\app_data.mdb (hoặc acdb)
2. FrontEnd là phần ứng dụng (form/ report).. cái này thì copy trên máy của người dùng
Sau đó bạn thực hiện chức năng linktable (liên kết bảng) đến tất cả các bảng cần sử dụng bằng cách trỏ đến địa chỉ \\server\data\app_data.mdb
Với cách làm này, khi mở frontend tại máy trạm của từng cá nhân, access sẽ ghi nhận phiên làm việc và quản lý để tránh bị xung đột trong quá trình xử lý.
+ Để đảm bảo nhiều người không thể sửa một bản ghi cùng lúc: khi thiết kế form, lưu ý thiết lập mục Record Locks ở chế độ "Edited record"
+ Trường ID của bảng thì nên để ở dạng Autoincrement (tự tăng) và bạn không phải quản lý việc sinh id mới như nào nữa.
GỢI Ý: Tôi rất ngạc nhiên là thấy có nhiều người, kể cả những anh/ chị có kinh nghiệm rồi mà khi thiết kế bảng dữ liệu vẫn để trường khóa (primary key) ở dạng người dùng tự sinh (kiểu ABC001 ... ABC002). Phải nói rằng đây là một thói quen không hợp lý vì các bạn sẽ phải viết hàng đống thủ tục để quản lý nó để tránh phát sinh xung đột dữ liệu.
Khi thiết kế trường khóa, tốt nhất là dùng kiểu số Autoincrement của Access để Access quản lý cái này tự động cho bạn. Còn nếu muốn có số hiệu tăng dần nào khác thì quản lý ở cấp người dùng sau khi thêm trường khóa ID (Auto increment) vào, bạn thêm trường mới và bạn quản lý nó theo cách của bạn.
TRÁNH VIỆC liên kết trường giữa các bảng bằng trường bạn tạo riêng này, và
CHỈ NÊN dùng ID dể liên kết khi thiết lập quan hệ các bảng!
paulsteigel > 12-09-21, 03:02 PM
(12-09-21, 11:04 AM)Major0418 Đã viết: Mô hình Backend và Frontend chính là mô hình mình sẽ triển khai.Đó là chính là điều không hợp lý! Số công văn không nên là trường khóa để kiểm soát liên kết bảng.
File mình up lên chỉ là ví dụ. Trong database mình làm, mình cũng đã bỏ Primary Key cho trường ID (tự gán số)
Còn đối với việc đặt ID là Auto Increment, có phải ý bạn là Auto Number? Lý do mình không để Auto Number vì ví dụ nếu người thứ nhất vào nhập Record sẽ được gán số 10, người thứ hai sẽ được gán số 11. Nhưng nếu người thứ nhất thoát không lưu Record thì người thứ ba sau đó sẽ tiếp tục được gán số 12 chứ không lấy lại được số 10 mà người thứ nhất đã bỏ qua. Vì Table mình thiết kế giống như kiểu lấy số công văn đó ạ nên không được bỏ trống số.
tranthanhan1962 > 12-09-21, 04:35 PM
Major0418 > 12-09-21, 09:18 PM
(12-09-21, 03:02 PM)paulsteigel Đã viết:(12-09-21, 11:04 AM)Major0418 Đã viết: Mô hình Backend và Frontend chính là mô hình mình sẽ triển khai.Đó là chính là điều không hợp lý! Số công văn không nên là trường khóa để kiểm soát liên kết bảng.
File mình up lên chỉ là ví dụ. Trong database mình làm, mình cũng đã bỏ Primary Key cho trường ID (tự gán số)
Còn đối với việc đặt ID là Auto Increment, có phải ý bạn là Auto Number? Lý do mình không để Auto Number vì ví dụ nếu người thứ nhất vào nhập Record sẽ được gán số 10, người thứ hai sẽ được gán số 11. Nhưng nếu người thứ nhất thoát không lưu Record thì người thứ ba sau đó sẽ tiếp tục được gán số 12 chứ không lấy lại được số 10 mà người thứ nhất đã bỏ qua. Vì Table mình thiết kế giống như kiểu lấy số công văn đó ạ nên không được bỏ trống số.
Autonumber là một công cụ giúp cho trường khóa không bao giờ bị trùng lặp, việc bỏ quãng (vì xóa, vì chưa lưu) không phải là vấn đề của thiết kế CSDL bạn nhé!
Trường khóa là để đảm bảo mối quan hệ bảng >> bảng đảm bảo luôn nhất quán.
Tôi đã làm access gần 20 năm và 15 năm trước tôi cũng từng nghĩ như bạn và sau đó khi gặp quá nhiều vướng víu vì các thủ tục xử lý khi xây dựng quan hệ 1>nhiều thì phát hiện ra vấn đề.
Không ai cản trở bạn việc gán số công văn tăng dần đều, nhưng không nên lấy id để làm số công văn mà hãy thiết lập một trường khác để làm điều này!
Về tổng quát thì tôi góp ý như vậy! Việc để Access quản lý trường quá là một kinh nghiệm thực hành lập trình nên theo! Còn bạn muốn làm theo cách của mình thì cũng không sao!
Chúc bạn thành công!
Major0418 > 12-09-21, 09:33 PM
(12-09-21, 04:35 PM)tranthanhan1962 Đã viết: <Tự động lưu và cập nhật Record khi Open Form> Thực là một suy nghĩ kỳ lạ. Mỗi khi 1 người mở CSDL và đóng lại vì mở nhầm sẽ có 1 record rác (vì record đó ngoài giá trị của field ID thì không có gì cả) và sau 1 thời gian CSDL đầy rác.
CSDL nhiều người dùng vẫn bị sự cố xung đột dữ liệu khi có nhiều người mở form nhập liệu hoặc xử lý cùng thời điểm (nhiều người cùng lảm việc / 1 record), chứ không chỉ nhập mới. Nên vấn đề không thể giải quyết đơn giản như suy nghĩ cuả bạn. Cách xử lý:
1/ Tạo Backend, Frontend, linktable như paulsteigel hướng dẫn.
2/ Nếu bạn dùng autonumber tạo ID thì gán cho mỗi user Frontend 1 mã (ví dụ: user1, user2, user3...), ID=<user & autonumber> thì ID không bao giờ bị trùng. Nếu 1 autonumber bị trùng sẽ khác nhau user (ví dụ: user115/user215, user220/user720...)
3/Thiết đặt Record Locks cho form, ưu tiên cho user tiếp cận với form trước để tránh xung đột dữ liệu.
tranthanhan1962 > 12-09-21, 10:39 PM
(12-09-21, 09:33 PM)Major0418 Đã viết: Vâng, cảm ơn bạn, file mình làm cũng theo cách này, còn trên chỉ là ví dụ thôi.Không tránh khỏi việc nhiều người vào cùng nhau và save cùng lúc được (vì thời gian load form và save tương đối chậm), nhưng dùng Record Locks xử lý thì được nó được tính bằng mili giây. Thủ thuật này bắt buột phải sử dụng cho CSDL nhiều user.
Còn việc gán Autonumber cho mỗi user cũng hơi khó vì như mình nói mục đích nhằm lấy số công văn, đó là số chung của cả phòng, tăng đều như 1999, 2000, 2001, 2002, người xử lý khác nhau nhưng số thì lại không được trùng nhau nên việc đặt user1, 2, 3 thì số gán kèm sau user1, 2, 3 vẫn trùng nhau như số 15 và 20 bạn nêu.
Vì vậy nên mình mới đặt phần này bằng DMax để nó tự gán bằng giá trị lớn nhất hiện có cộng thêm 1. Nhưng lại vướng phải tình trạng 2 người vào cùng lúc thì được gán số giống nhau. VÌ vậy nên mới muốn khi người 1 vào thì nó save luôn record để trong record có giá trị số lớn nhất thì người sau vào sẽ là số sau luôn, nhưng hiện nay người thứ nhất vào thì trong table vẫn chưa có record của người 1 cho đến khi người 1 nhập đủ các field, nên người 2 vẫn bị gán số đã gán trước đó cho người 1.
paulsteigel > 12-09-21, 10:42 PM
(12-09-21, 09:33 PM)Major0418 Đã viết: Vâng, cảm ơn bạn, file mình làm cũng theo cách này, còn trên chỉ là ví dụ thôi.
Còn việc gán Autonumber cho mỗi user cũng hơi khó vì như mình nói mục đích nhằm lấy số công văn, đó là số chung của cả phòng, tăng đều như 1999, 2000, 2001, 2002, người xử lý khác nhau nhưng số thì lại không được trùng nhau nên việc đặt user1, 2, 3 thì số gán kèm sau user1, 2, 3 vẫn trùng nhau như số 15 và 20 bạn nêu.
Vì vậy nên mình mới đặt phần này bằng DMax để nó tự gán bằng giá trị lớn nhất hiện có cộng thêm 1. Nhưng lại vướng phải tình trạng 2 người vào cùng lúc thì được gán số giống nhau. VÌ vậy nên mới muốn khi người 1 vào thì nó save luôn record để trong record có giá trị số lớn nhất thì người sau vào sẽ là số sau luôn, nhưng hiện nay người thứ nhất vào thì trong table vẫn chưa có record của người 1 cho đến khi người 1 nhập đủ các field, nên người 2 vẫn bị gán số đã gán trước đó cho người 1.
Major0418 > 13-09-21, 11:45 PM
(12-09-21, 10:42 PM)paulsteigel Đã viết:(12-09-21, 09:33 PM)Major0418 Đã viết: Vâng, cảm ơn bạn, file mình làm cũng theo cách này, còn trên chỉ là ví dụ thôi.
Còn việc gán Autonumber cho mỗi user cũng hơi khó vì như mình nói mục đích nhằm lấy số công văn, đó là số chung của cả phòng, tăng đều như 1999, 2000, 2001, 2002, người xử lý khác nhau nhưng số thì lại không được trùng nhau nên việc đặt user1, 2, 3 thì số gán kèm sau user1, 2, 3 vẫn trùng nhau như số 15 và 20 bạn nêu.
Vì vậy nên mình mới đặt phần này bằng DMax để nó tự gán bằng giá trị lớn nhất hiện có cộng thêm 1. Nhưng lại vướng phải tình trạng 2 người vào cùng lúc thì được gán số giống nhau. VÌ vậy nên mới muốn khi người 1 vào thì nó save luôn record để trong record có giá trị số lớn nhất thì người sau vào sẽ là số sau luôn, nhưng hiện nay người thứ nhất vào thì trong table vẫn chưa có record của người 1 cho đến khi người 1 nhập đủ các field, nên người 2 vẫn bị gán số đã gán trước đó cho người 1.
Để giải quyết được vấn đề số công văn, bạn có thể tận dụng nguyên tắc: ai nhấn nút lưu trước, người đó sẽ được nhận số văn bản trước và việc gắn số văn bản sẽ nằm trong sự kiện nhấn nút Lưu/Save.
Để làm thế bạn cần lưu ý:
1. Một khi bấm nút lưu thì không thể xóa được nghiệp vụ văn bản (cái này là để đảm bảo quy định trong lưu trữ văn bản);
2. Viết một thủ tục laysovanban() riêng và thủ tục này làm nhiệm vụ lấy số thứ tự văn bản gần nhất có trong csdl + 1 >> kết thúc
3. Tại thủ tục lưu bạn làm thêm một lệnh gán giá trị từ số tìm được đó về số công văn;
Một điều bạn cân lưu ý: Khi người dùng xoay nút xoay trên chuột thì form sẽ tự động update, thêm bản ghi vào csdl. vì thế bạn nên đặt một thủ tục kích hoạt, hỏi có lưu không trong sự kiện before_insert của Form. Nút lưu/save cũng sẽ kích hoạt sự kiện này khi bạn thêm công văn do đó chỉ cần đặt lệnh kiểm tra, gán số công văn ở sự kiện Form_beforeInsert là đủ