mercredi 3 avril 2019

Generic UnitOfWork

I am trying to create a Repository & UnitOfWork for Data Access Layer. In my current implementation I have to modify my UnitOfWork everytime I create a new repository. I would like to avoid that and also keep the functionality to extend my repository abstract class.

Following is my generic Repository & UnitOfWork interface & classes

public interface IRepositoryBase<T> where T : class
{
    IList<T> FindAll();
    T FindByCondition(Expression<Func<T, bool>> expression);
    void Create(T entity);
    void Update(T entity);
    void Delete(T entity);
}

public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
    protected DBContext _dbContext { get; set; }

    public RepositoryBase(DBContext dbContext)
    {
        _dbContext = dbContext;
    }
    //other methods removed
    public void Create(T entity)
    {
        _dbContext.Set<T>().Add(entity);
    }
}

public interface IUnitOfWork : IDisposable
{
    IReminderRepository Reminder { get; }
    void Save();
}

public class UnitOfWork : IUnitOfWork
{
    protected DBContext _dbContext { get; set; }
    private IReminderRepository _reminderRepository;

    public UnitOfWork(DBContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IReminderRepository Reminder
    {
        get
        {
            return _reminderRepository = _reminderRepository ?? new ReminderRepository(_dbContext);
        }
    }

    public void Save()
    {
        _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        _dbContext.Dispose();
    }
}

Here I can extend my Repository as per my specific needs by implementing the specific Repository as

public interface IReminderRepository : IRepositoryBase<Reminder>
{
    IList<Reminder> GetAllReminders();
    Reminder GetReminderById(Guid id);    
    Reminder GetReminderByName(string name);    
    void CreateReminder(Reminder reminder);    
    void UpdateReminder(Reminder reminder);    
    void DeleteReminder(Reminder reminder);    
}

public class ReminderRepository : RepositoryBase<Reminder>, IReminderRepository
{
    public ReminderRepository(DBContext dbContext)
    : base(dbContext)
    {
        _dbContext = dbContext;
    }
    //other methods removed
    public Reminder GetReminderByName(string name)
    {
        return FindAll()
            .OrderByDescending(r => r.Name)
            .FirstOrDefault(r => r.Name == name);

        //return FindByCondition(r => r.Name == name);
    }
}

This is ok but when ever I will create a new Specific Repository I will have to modify the UnitOfWork class as well by adding a new property for the new Repository.

While searching online I found following but it does not work in my case as my RepositoryBase is an abstract class.

public interface IUnitOfWork : IDisposable
{
    Dictionary<Type, object> _repositories;
    void Save();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly DBContext _dbContext { get; set; }
    private readonly Dictionary<Type, object> _repositories = new Dictionary<Type, object>();

    public Dictionary<Type, object> Repositories
    {
        get { return _repositories; }
        set { Repositories = value; }
    }

    public UnitOfWork(DBContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IRepositoryBase<T> Repository<T>() where T : class
    {
        if (Repositories.Keys.Contains(typeof(T)))
        {
            return Repositories[typeof(T)] as IRepositoryBase<T>;
        }

        IRepositoryBase<T> repo = new RepositoryBase<T>(_dbContext);//This does not work
        Repositories.Add(typeof(T), repo);
        return repo;
    }

    public void Save()
    {
        _dbContext.SaveChanges();
    }
}

Aucun commentaire:

Enregistrer un commentaire