Tips and Tricks #53: Apply Repository Pattern for Data Access

Abstract data access logic behind a clean interface for testability and flexibility.

Code Snippet

// IRepository.cs
public interface IRepository where T : class
{
    Task GetByIdAsync(int id);
    Task> GetAllAsync();
    Task AddAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(int id);
}

// UserRepository.cs
public class UserRepository : IRepository
{
    private readonly DbContext _context;
    
    public UserRepository(DbContext context) => _context = context;
    
    public async Task GetByIdAsync(int id) =>
        await _context.Users.FindAsync(id);
    
    public async Task> GetAllAsync() =>
        await _context.Users.ToListAsync();
    
    // ... other methods
}

// Easy to mock in tests
public class FakeUserRepository : IRepository
{
    private readonly List _users = new();
    // ... in-memory implementation
}

Why This Helps

  • Decouples business logic from data access
  • Enables easy unit testing with mocks
  • Allows swapping data stores without code changes

How to Test

  • Unit test services with mock repository
  • Integration test repository against real DB

When to Use

Any application with data persistence. Essential for clean architecture.

Performance/Security Notes

Don’t over-abstract. Generic repositories can become leaky abstractions for complex queries.

References


Try this tip in your next project and share your results in the comments!


Discover more from Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.