Courses/C#/Repository Pattern
    Back to Course

    Lesson 35: Repository Pattern & Unit of Work

    Abstract your data access with the Repository pattern and coordinate transactions with Unit of Work.

    What You'll Learn

    • • Generic Repository with CRUD operations
    • • Specialized repositories for domain-specific queries
    • • Unit of Work pattern for transactional consistency
    • • Wiring everything together with Dependency Injection

    🧠 Real-World Analogy

    A Repository is like a librarian — you ask for books by criteria, and the librarian finds them without you needing to know which shelf they're on. The Unit of Work is like a shopping cart — you add multiple items, and they're all purchased (committed) together, or none at all if your card declines (rollback).

    Generic & Specialized Repositories

    A generic repository provides standard CRUD operations for any entity. Specialized repositories extend it with domain-specific queries (like "get recent orders" or "calculate total revenue"). This keeps your service layer clean and testable.

    Generic & Specialized Repositories

    Build a generic IRepository<T> and extend it with domain-specific OrderRepository.

    Try it Yourself »
    C#
    using System;
    using System.Linq.Expressions;
    using Microsoft.EntityFrameworkCore;
    
    // Generic Repository Interface
    public interface IRepository<T> where T : class
    {
        Task<T?> GetByIdAsync(int id);
        Task<IEnumerable<T>> GetAllAsync();
        Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate);
        Task AddAsync(T entity);
        void Update(T entity);
        void Delete(T entity);
    }
    
    // Generic Repository Implementation
    public class Repository<T> : IRepository<T> where T : class
    {
      
    ...

    Unit of Work

    The Unit of Work pattern groups multiple repository operations into a single transaction. It holds references to all repositories and shares the same DbContext, ensuring SaveChanges() commits all changes atomically.

    Unit of Work Pattern

    Coordinate multiple repositories with transactional Unit of Work.

    Try it Yourself »
    C#
    using System;
    using Microsoft.EntityFrameworkCore;
    
    // Unit of Work — coordinates multiple repositories
    public interface IUnitOfWork : IDisposable
    {
        IRepository<Customer> Customers { get; }
        IOrderRepository Orders { get; }
        IRepository<Product> Products { get; }
        
        Task<int> SaveChangesAsync();
        Task BeginTransactionAsync();
        Task CommitAsync();
        Task RollbackAsync();
    }
    
    public class UnitOfWork : IUnitOfWork
    {
        private readonly AppDbContext _context;
        private IDbC
    ...

    Putting It Together

    In your service layer, inject IUnitOfWork and use it to coordinate business operations. If placing an order involves checking stock, creating the order, and reducing inventory, all operations succeed or fail together.

    OrderService Using Unit of Work

    Place an order with atomic stock reduction and transaction management.

    Try it Yourself »
    C#
    using System;
    using Microsoft.Extensions.DependencyInjection;
    
    // Service that uses Unit of Work
    public class OrderService
    {
        private readonly IUnitOfWork _uow;
        
        public OrderService(IUnitOfWork uow) => _uow = uow;
        
        public async Task PlaceOrderAsync(int customerId, List<(int productId, int qty)> items)
        {
            await _uow.BeginTransactionAsync();
            
            try
            {
                // Validate customer exists
                var customer = await _uow.Customers.GetByIdAs
    ...

    Pro Tip

    Some architects argue that EF Core's DbContext is already a Unit of Work and DbSet<T> is already a Repository. For simple apps, using DbContext directly is fine. Use Repository + UoW when you need testability, multiple data sources, or complex business transactions.

    Common Mistakes

    • • Creating a new DbContext per repository — they must share the same context
    • • Exposing IQueryable from repositories — leaks EF details to upper layers
    • • Forgetting to register repositories as Scoped — Transient creates separate contexts

    Lesson Complete!

    You've mastered Repository and Unit of Work patterns. Next, secure your APIs with JWT authentication and authorization.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service