1. Backend
  2. Repository Pattern

Repositories

Each domain object (Entity/Model) has its own Repository interface and implementation.

For example, for the User domain model, there’s IUserRepository.cs and UserRepository.cs.

Interface

src/ProjectName.Application/Repositories/Core/IUserRepository.cs
...
namespace ProjectName.Application.Repositories.Core
{
    public interface IUserRepository : IRepository<User>
    {
        User GetByEmail(string email);
        Task<User> GetByEmailAsync(string email);
        ...
    }
}

Implementation

src/ProjectName.Infrastructure/Repositories/Core/UserRepository.cs
...
namespace ProjectName.Infrastructure.Repositories.Core
{
    public class UserRepository : MasterRepository<User>, IUserRepository
    {
        public UserRepository(MasterDbContext context) : base(context)
        {
        }

        public User GetByEmail(string email)
        {
            return Context.Users.Include(f => f.Tenants).SingleOrDefault(f => f.Email == email.ToLower().Trim());
        }

        public async Task<User> GetByEmailAsync(string email)
        {
            return await Context.Users
                .Include(f => f.Tenants).ThenInclude(f=>f.Tenant)
                .FirstOrDefaultAsync(f => f.Email == email.ToLower().Trim());
        }
        ...
    }
}

Unit of Work

The repositories cannot Save to database, that’s the Unit of Work implementation’s duty.

So this is a mistake:

...
public interface IUserRepository : IRepository<User>
    {
        ...
        Task DeleteUser(int userId);

You need to do it this way:

var user = ...
_masterUnitOfWork.Users.Add(user);
await _masterUnitOfWork.CommitAsync();

To learn more about the Repository Pattern common mistakes, go to Mosh Hamedani blog post.