Pattern Library
Design patterns used throughout the template with examples
ReferenceIntermediate• 20 min read
Repository Pattern
Encapsulates data access logic and provides a consistent interface for data operations
Interface Definition
public interface IUserRepository : IRepository<User, Guid>
{
Task<User?> GetByEmailAsync(string email, CancellationToken cancellationToken = default);
Task<bool> IsEmailUniqueAsync(string email, Guid? excludeUserId = null, CancellationToken cancellationToken = default);
Task<IReadOnlyList<User>> GetActiveUsersAsync(CancellationToken cancellationToken = default);
}
Implementation
public class UserRepository : Repository<User, Guid>, IUserRepository
{
public UserRepository(ApplicationDbContext context) : base(context) { }
public async Task<User?> GetByEmailAsync(string email, CancellationToken cancellationToken = default)
{
return await Context.Users
.FirstOrDefaultAsync(u => u.Email == email, cancellationToken);
}
public async Task<bool> IsEmailUniqueAsync(string email, Guid? excludeUserId = null, CancellationToken cancellationToken = default)
{
return !await Context.Users
.AnyAsync(u => u.Email == email && u.Id != excludeUserId, cancellationToken);
}
}
Benefits
- • Centralizes data access logic
- • Makes testing easier with mocking
- • Provides consistent query interfaces
- • Supports dependency injection
Unit of Work Pattern
Maintains a list of objects affected by a business transaction and coordinates changes
Interface & Implementation
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
IRefreshTokenRepository RefreshTokens { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
Task CommitTransactionAsync(CancellationToken cancellationToken = default);
Task RollbackTransactionAsync(CancellationToken cancellationToken = default);
}
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public IUserRepository Users { get; }
public IRefreshTokenRepository RefreshTokens { get; }
public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
await DispatchDomainEventsAsync();
return await _context.SaveChangesAsync(cancellationToken);
}
}
Usage Example
public async Task<UserResponse> CreateUserAsync(CreateUserRequest request)
{
var user = new User(request.Email, request.DisplayName);
await _unitOfWork.Users.AddAsync(user);
await _unitOfWork.SaveChangesAsync(); // Saves all changes atomically
return _mapper.MapToUserResponse(user);
}