Tips and Tricks #213: 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 Byte Architect

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.