Tutorials ASP.NET Core Complete Tutorial (ShopNest)
EF Core Repository Pattern and Unit of Work
Learn EF Core Repository Pattern and Unit of Work in our free ASP.NET Core Complete Tutorial (ShopNest) series. Step-by-step explanations, examples, and interview tips on Toolliyo Academy.
On this page
Introduction
The Repository + Unit of Work pattern wraps EF Core behind interfaces so ShopNest's shopping cart logic is testable with mocks and controllers stay thin. Teams debate whether it's essential — this lesson shows both sides with a working cart.
After this article you will
- Implement IRepository<T> and specific repositories
- Coordinate saves with IUnitOfWork
- Register repositories in DI
- Unit test CartService with mocked IProductRepository
- Evaluate repository vs direct DbContext trade-offs
Prerequisites
- Article 18 — EF Core Fluent API
- ShopNest DbContext with Products/Orders from Articles 13–15
- SQL Server or LocalDB configured
Concept deep-dive
public interface IRepository<T> where T : class
{
Task<T?> GetByIdAsync(int id, CancellationToken ct = default);
Task AddAsync(T entity, CancellationToken ct = default);
void Update(T entity);
void Remove(T entity);
}
public interface IUnitOfWork : IAsyncDisposable
{
IProductRepository Products { get; }
ICartRepository Carts { get; }
Task<int> SaveChangesAsync(CancellationToken ct = default);
}
public class UnitOfWork : IUnitOfWork
{
private readonly ShopNestDbContext _db;
public UnitOfWork(ShopNestDbContext db) => _db = db;
public IProductRepository Products => new ProductRepository(_db);
public ICartRepository Carts => new CartRepository(_db);
public Task<int> SaveChangesAsync(CancellationToken ct = default)
=> _db.SaveChangesAsync(ct);
}
Debate: EF Core DbContext already implements Unit of Work + Repository. Extra layer adds boilerplate but helps when swapping data access in tests or multi-database scenarios. Microsoft docs: often skip generic repository for simple apps.
Hands-on — ShopNest Online Shopping Cart
- ICartRepository with GetOrCreateCartAsync(userId).
- CartService.AddItemAsync — uses IUnitOfWork, not DbContext directly.
- xUnit test: mock IProductRepository returns product; verify AddAsync called.
- Register:
services.AddScoped<IUnitOfWork, UnitOfWork>();
Common errors & best practices
- Repository wrapping every DbSet with no added value — prefer specific repos with domain queries.
- Singleton UnitOfWork — must be Scoped per request.
Interview questions
Q: Is Repository an antipattern over EF?
A: Generic repo over DbSet adds little; specific repos with domain queries still help testability in large teams.
Q: Unit of Work purpose?
A: Single SaveChanges across multiple repos in one transaction boundary.
Summary
- Repository abstracts data access for testability
- Unit of Work shares one DbContext per request
- Shopping cart demo ties products, cart lines, SaveChanges
- Skip generic repo if team prefers DbContext + mock in tests
Previous: EF Core Fluent API
Next: EF Core Performance Optimization
FAQ
Should ShopNest use Repository everywhere?
Start with DbContext in small modules; add repos when testing or swapping storage becomes painful.
How mock in tests?
Moq IProductRepository — no in-memory DB required for pure service tests.
Sign in to ask a question or upvote helpful answers.
No questions yet — be the first to ask!