Kết hợp Unit Of Work và Repository Pattern trong ASP.NET MVC
Unit Of Work là một khái niệm liên quan đến hiệu quả của việc triển khai Repository Pattern. Để hiểu khái niệm này sâu hơn thì điều quan trọng là hiểu được khái niệm Repository Pattern. Chúng ta sẽ không đi sâu vào khái niệm Repository Pattern vì tôi đã trình bày trong bài viết: http://tedu.com.vn/lap-trinh-aspnet/tim-hieu-ve-repository-pattern-va-generic-repository-pattern-36.html Nhưng chúng ta sẽ nhắc lại một chút để hiểu được các ý cần thiết.
Repository Pattern
Một repository nó không là gì cả, nó chỉ là một class được định nghĩa cho một thực thể, với tất cả các hành động có thể cho một thực thể đó. Ví dụ như một repository cho một thực thể là Customer, sẽ có các phương thức CRUD (Cread Read Update Delete) hoặc bất cứ hành động nào có thể liên quan đến thực thể này. Một Repository Pattern có thể được triển khai theo các cách sau:
- Một Repository cho một Entity: Kiểu triển khai này tập trung việc sử dụng một repository cho một thực thể cụ thể. Ví dụ nếu bạn có 2 thực thể là Order và Customer, mỗi thực thể này sẽ có một repository của riêng nó là OrderRepository và CustomerRepository.
- Generic Repository: Một generic repository là một cái có thể sử dụng cho tất cả các thực thể, hay nói cách khác chúng được sử dụng cho cả Order và Customer hoặc bất cứ Entity nào khác.
Unit Of Work trong Repository Pattern
Unit Of Work được sử dụng để đảm bảo nhiều hành động như insert, update, delete...được thực thi trong cùng một transaction thống nhất. Nói đơn giản hơn, nghĩa là khi một hành động của người dùng tác động vào hệ thống, tất cả các hành động như insert, update, delete...phải thực hiện xong thì mới gọi là một transaction thành công. Gói tất cả các hành động đơn lẻ vào một transaction để đảm bảo tính toàn vẹn dữ liệu.
Để hiểu khái niệm này, hãy xem cách triển khai Repository Pattern sau đây sử dụng non-generic Repository Pattern cho thực thể Customer:
.jpg)
Đoạn code trên nhìn có vẻ đúng. Nhưng có một vấn đề ở đây khi chúng ta thêm một repository cho thực thể khác ví dụ như Order. Trong trường hợp này cả hai repository sẽ cùng phải khởi tạo, và sử dụng trên đối tượng DbContext của riêng nó. Điều này sẽ có rủi ro trong tương lai khi một trong 2 hàm SaveChange() của một trong 2 repository bị lỗi và cái kia thành công nên dữ liệu trong cơ sở dữ liệu sẽ bị sai. Đây là lúc mà Unit Of Work cần dùng đến.
Để ngăn chặn điều này, chúng ta sẽ thêm một tầng mới hoặc một tầng trung gian giữa Controller và Customer Repository. Lớp này sẽ tập trung hóa việc lưu trữ cho tất cả các Repository để nhận đối tượng thể hiện của DbContext. Điều này đảm bảo rằng mỗi một transaction sẽ dùng chung 1 thể hiện của DbContext cho tất cả các Repository liên quan. Hoặc là thành công tất cả hoặc thất bại cũng thất bại tất cả. Trong ví dụ trên khi thêm dữ liệu cho Order và Customer trong một transaction duy nhất, cả hai sẽ sử dụng cùng 1 thể hiện của DbContext. Trường hợp nếu không dùng và có dùng Unit Of Work có thể được trình bày như sau:

Trong trình bày hình ảnh trên, trong khi một hành động xảy ra, cả Customer và Order đều sử dụng chung một đối tượng của lớp DbContext. Điều này sẽ đảm bảo ngay cả khi một trong hai bị lỗi, cái kia sẽ không được lưu lại, vì thế database sẽ toàn vẹn. Khi SaveChange() được thực thi, nó sẽ thành công khi cả 2 hành động trên 2 Repository được thực hiện xong.
Chúng ta hãy cùng triển khai khái niệm này cho ví dụ trên. Chúng ta sẽ thêm mới 1 class tên là UnitOfWork và class này sẽ nhận thể hiện của lớp DbContext. Class này cũng tạo ra thể hiện cho các Repository cần thiết hay nói cách khác thì các thể hiện của Repository Order và Customer đều được sử dụng chung 1 đối tượng DbContext:

Và Customer Repository của chúng ta sẽ được thay đổi để nhận đối tượng của DbContext từ Class Unit Of Work như đoạn code dưới đây:

Tương tự, chúng ta có thể làm với Order Repository. Cuối cùng Controlelr của chúng ta sẽ như sau:

Cả hai Repository là Order và Customer sử dụng chung một thể hiện của lớp DbContext và thực thi phương thức SaveChange() sử dụng thể hiện của Unit Of Work. Transaction chỉ hoàn thành khi cả 2 hành động trên 2 repository cùng hoàn thành hoặc sẽ không có cái nào cả. Các bạn có thể làm theo ví dụ để thấy.
Nếu có thắc mắc gì về khái niệm của Unit Of Work với Repository Pattern. Xin vui lòng comment phía dưới.
Trích nguồn từ: www.c-sharpcorner.com
Bài viết liên quan
Nâng cấp RAG thành Agentic RAG với Dynamic Toolcall | Xây dựng RAG AI
Vậy làm thế nào để nâng cấp RAG thành một hệ thống Agentic RAG thông minh hơn, có khả năng tự động quyết định khi nào và nên gọi tool nào? Câu trả lời chính là Dynamic Toolcall.
Đọc thêm
Tối ưu kết quả trả về từ VectorDB với Scoring và Fingerprint | Xây dựng RAG AI
Đến Phần 3 này, chúng ta sẽ cùng nâng cấp khả năng tìm kiếm và truy vấn dữ liệu từ VectorDB.
Đọc thêmTrang bị Memory cho RAG bằng Vector Database với Qdrant
Ở phần tiếp theo này, chúng ta sẽ tiến thêm một bước quan trọng: trang bị bộ nhớ (Memory) cho RAG bằng cách sử dụng Vector Database Qdrant.
Đọc thêm
Hướng dẫn tạo ứng dụng ASP.NET Core (.NET 8) và chuẩn bị kết nối OpenAI Chat Model để xây dựng RAG AI
Trong bài viết này, chúng ta sẽ bắt đầu một hành trình nhỏ: xây dựng một ứng dụng RAG AI (Retrieval-Augmented Generation).
Đọc thêm
Ra mắt khóa học: TEDU-53: Xây dựng ứng dụng CMS với ASP.NET Core 8.0 + Angular.
Ngay bây giờ các bạn có thể đăng ký thông qua mã giảm giá tại trang chi tiết khóa học. Mã giảm giá sẽ được vô hiệu hóa khi đủ số lượng người theo thang bậc.
Đọc thêm
10 thủ thuật để tăng tốc độ ứng dụng .NET Core 3.x
Trong bài viết này mình sẽ đưa ra 10 mẹo để giúp bạn tăng tốc ứng dụng ASP.NET Core 3.
Đọc thêm
Migrate hệ thống ASP.NET Core 2.2 lên 3.1
Bài viết này mình đúc kết lại sau khi migrate toàn bộ hệ thống TEDU hiện tại từ .NET Core 2.2 lên 3.1 chia sẻ lại để mọi người cùng trao đổi
Đọc thêm
Tìm hiểu Unit Testing trong ASP.NET Core
Tiếp theo bài viết trước với tiêu đề Tìm hiểu về Dependency Injection trong ASP.NET Core. Hôm nay mình sẽ tập trung vào unit test.
Đọc thêm
Tìm hiểu về Dependency Injection trong ASP.NET Core
Bài viết này chúng ta sẽ cùng tìm hiểu về những điều thú vị xung quanh depedency injection và unit testing.
Đọc thêm
Cách sử dụng Yarn trong Visual Studio 2017
Cách sử dụng Yarn để quản lý các dependencies trong Visual Studio 2017
Đọc thêm