Repository
An intermediary between the domain and storage, exposing illusory in-memory collections.
Context
You want to work with your domain as if they were collections, without knowing if SQL, NoSQL, or an API is behind the scenes.
Problem
- Mixing business logic with SQL contaminates the domain.
- Changing persistence requires modifying the domain.
Solution
An IXxxRepository interface with Add, GetById, Find that hides persistence.
#Example in C#
public interface IOrderRepository
{
Task<Order?> GetAsync(Guid id);
Task<IReadOnlyList<Order>> FindByCustomerAsync(Guid customerId);
void Add(Order order);
void Remove(Order order);
}
public class EfOrderRepository : IOrderRepository
{
private readonly AppDbContext _db;
public EfOrderRepository(AppDbContext db) => _db = db;
public Task<Order?> GetAsync(Guid id) => _db.Orders.FindAsync(id).AsTask();
public Task<IReadOnlyList<Order>> FindByCustomerAsync(Guid customerId) =>
_db.Orders.Where(o => o.CustomerId == customerId).ToListAsync()
.ContinueWith(t => (IReadOnlyList<Order>)t.Result);
public void Add(Order o) => _db.Orders.Add(o);
public void Remove(Order o) => _db.Orders.Remove(o);
}When NOT to use it
- With EF Core, you already have a repository (
DbSet<T>). Encapsulating it adds noise unless the domain contract is narrower (read models, specific queries). - For simple reads → consider CQRS with direct queries.
Tradeoffs
| Pro | Con |
|---|---|
| Isolates the domain from the ORM | A thin layer that often just delegates |
| Tests with fake repositories | Risk of exposing LINQ and EF filtering to the domain |
#extra #ddd #persistence