🧩 Design Patterns
Repository Pattern
Abstracting persistence behind a collection-like interface.
A Repository presents domain code with a collection-like interface (GetById, Add, Remove) over
persistence, hiding EF Core/SQL specifics from the rest of the app. The honest, senior-level nuance to
mention: with EF Core, DbContext already implements Unit of Work and its DbSet already looks
a lot like a repository — a hand-rolled generic IRepository on top of EF Core can be redundant
ceremony ("just wraps DbSet"). The pattern earns its keep when you need to (a) genuinely swap
persistence technology, (b) centralize non-trivial query logic (specifications), or (c) keep domain
code testable without spinning up a real/in-memory DbContext in every test.
public interface IOrderRepository
{
Task<Order?> GetByIdAsync(Guid id);
Task AddAsync(Order order);
Task<IReadOnlyList<Order>> GetByCustomerAsync(string customerId);
}
public class EfOrderRepository(AppDbContext db) : IOrderRepository
{
public Task<Order?> GetByIdAsync(Guid id) => db.Orders.FindAsync(id).AsTask();
public Task AddAsync(Order order) { db.Orders.Add(order); return Task.CompletedTask; }
public Task<IReadOnlyList<Order>> GetByCustomerAsync(string customerId) =>
db.Orders.Where(o => o.CustomerId == customerId).ToListAsync()
.ContinueWith(t => (IReadOnlyList<Order>)t.Result);
}
Flashcards (2)
What's the honest critique of adding a generic IRepository<T> on top of EF Core's DbSet<T>?
tap to reveal answer
What three concrete reasons justify a Repository abstraction even when using EF Core?
tap to reveal answer