Loading...
...
Posted by Firuza Polad on June 17, 2025

Non-Generic Reposiory pattern vs Generic Reposiory pattern

Is a class to handle all possible DB operations for an Entity. Is used to separate DAL logic from BS logic of application, It acts as a mediator between them. Example: Repository for Employee entities, define all CRUD operations and other operations related to Employee. Provide a way to manage CRUD operations without directly interacting with DB, instead of writing DB queries directly in BS logic, we use IEmployeeRepository and EmployeeRepository class to handle, then EmployeeService in BL layer just depend on IEmployeeRepository, not actual DB. So BS logic does not need to know if data coming from DB, service or any source, just interacting with repository to handle task. Make code more cleaner and flexible, easy to write unit testing. RP implemented in 2 ways:
Non-Generic Repository (one repository per Entity):Custom repository class for each entity, eg: UserRepository, EmployeeRepository.
Generic Repository (one repository for all Entity): Is an implementation of Repository pattern that allows us to create a single repository that can be used for multiple entities. Instead of writing sperate repositories for each entity, GR uses a single class with Generic type T parameter to handle CRUD. Simplifies DAL by reducing duplicate logic.

Code Example for Non-Generic Reposiory pattern


Controller (API Layer): Handles incoming HTTP requests and routes them to the appropriate service methods. It acts as a bridge between the client (frontend) and the BL. Example: GET `/api/employees/{id}` calls `EmployeeService.GetById(id)`.
Service (Business Logic Layer): Contains the core business logic and coordinates between the controller and the repository. Validates input, applies rules, and processes data before passing to/from the data layer.
Repository (Data Access Layer):Handles all interactions with the database. Encapsulates querying, inserting, updating, and deleting data. It allows services to work with data without knowing the source
Entity + DTO: -Entity: Represents the real database model (e.g., `Employee`) used with EF Core. - DTO (Data Transfer Object): A simplified version of Entity for transferring data between layers, especially to/from API.


Code Example for Generic Reposiory pattern


Controller (API Layer): This is the entry point of your application. It handles HTTP requests and responses. Calls methods from the Service Layer to execute business logic
Service (Business Logic Layer): Contains business logic and rules for handling application operations. Interacts with the Generic Repository to get or manipulate data.
Repository (Data Access Layer): Generic Repository handles all CRUD operations for any entity. You do not write a separate repository for each entity, ensure DRY principle.


Unit Of Work

Used to manage changes to multiple entities in a DB as a single Transaction (operation). If we want to implement transaction while using EF and RP, then UOF can be effective implementation of RP.
eg1: we are shopping and adding items to card, we don't want our order to be processed until we are done shopping and ready to checkout, the process should either complete all at once (everything in card purchased) or not at all (if something went wrong).
eg2: we have 2 account A (for debit card) and B (for credit card), money subtract from A and added to B, both must succeed together. If one of these operations are failed, like Debit operation is succeed but Credit operation is failed, then system could end up with incorrect balances, and UOW ensure that both either succeed or failed together.
eg3: in application that interact with DB , we might be making multiple changes , such as update profile while sending notification. The UOW group these changes together, when we are ready then UOW 'commmit' changes, so they are either all applied to DB, or none of them. UOW ensure that all operations completed successfully, reduce number of DB transaction by grouping changes.

Code Example for UOW


Controller (API Layer): This is the entry point of your application. It handles HTTP requests and responses. Calls methods from the Service Layer to execute business logic
Service (Business Logic Layer): Uses UoW to coordinate multiple repository operations.
Repository (Data Access Layer+UOW): Repositories don’t call SaveChanges() directly. Instead, they only perform data operation. The Unit of Work will call SaveChanges() once after all repositories finish their operations.


Transaction

Is a set of operations performed as a single operation, it has properties often called ACID:

  • Atomicity: all operation are completed successfully or non of them are, eg: if money from account A transferred to account B, and deposit fails for any reason, then all the money stays original account.
  • Consistency: DB start and end in a valid state after transaction, eg: if DB rule says that can not have a negative balance , even if multiple transaction happening at the same time consistency ensure that the rule is followed.
  • Isolation: transaction are like individual task that should not mixed with each other , so it can not see incomplete work of another transaction, eg: if 2 people buying last ticket for concert at the same time, isolation ensure that only 1 person successfully, other transaction will see it as no longer available.
  • Durability: once transaction complete successfully , its result are permanent, eg: after transfer money from 1 to another the money will transfer, even if there is power outage right after transaction is complete.

EF provide an interface that called IDbContextTransaction which manage DB transaction, allow manage transaction lifecycle , including start,commit,rollingback. We don't use IDbContextTransaction in constructor of UOW class, because transaction should be managed and created explicitly when needed, rather than automatically started when instance of class is created. We may not need transaction for every operation, and use it in constructor can lead on performance overhead, also if an exception occurs during constructor execution, it might leave transaction. To manage DB transaction we use these below methods, and we include them in Service layer rather than in generic repository.
  • BeginTransaction()-start transaction, it returns instance of IDbContextTransaction which we can use commit or rollback.
  • CommitAsync()- after performing DB operation, we commit to ensure that all operation are applied to DB.
  • RollbackAsync()- if something goes wrong (exception thrown) we can roll back transaction to ensure we leaving db its original state.
  • DisposeAysnc()-relasing any resources that it holds

Code Example for Transaction


We want to transfer money between two accounts. If debit from Account A or credit to Account B fails, the transaction must roll back.


Information
All diagrams, Folder structure, Code example in this blog were created by me using Lucid , Canva and IDE If you'd like to contribute, request more diagrams or text, or suggest improvements, feel free to contact me
© 2025 Firuza Polad. All rights reserved.

Let’s Connect

I’m open to collaboration, remote and freelance work!