Универсальный UnitOfWork - PullRequest
       58

Универсальный UnitOfWork

0 голосов
/ 03 апреля 2019

Я пытаюсь создать репозиторий и UnitOfWork для уровня доступа к данным.В моей текущей реализации мне приходится изменять мой UnitOfWork каждый раз, когда я создаю новый репозиторий.Я хотел бы избежать этого, а также сохранить функциональность для расширения моего абстрактного класса репозитория.

Ниже приводится мой общий интерфейс и классы репозитория и UnitOfWork

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 
{
    IReminderRepository Reminder { get; }
    void Save();
}

public class UnitOfWork : IUnitOfWork, IDisposable
{
    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();
    }
}

Здесь я могу расширить свой репозиторий какв соответствии с моими конкретными потребностями, реализовав конкретный репозиторий как

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);
    }
}

Это нормально, но когда я буду создавать новый репозиторий, мне придется также изменить класс UnitOfWork, добавив новое свойство для новогоРепозиторий.

При поиске в Интернете я обнаружил следующее, но в моем случае это не работает, так как мой RepositoryBase является абстрактным классом.

public interface IUnitOfWork 
{
    void Save();
}

public class UnitOfWork : IUnitOfWork, IDisposable
{
    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();
    }
}

1 Ответ

1 голос
/ 03 апреля 2019

Вам, очевидно, нужно получить ссылку на IReminderRepository где-нибудь в вашем коде, чтобы можно было использовать остальные специфические API.

Если вы не хотите расширять свой класс UnitOfWork для возврата IReminderRepository, вы можете создать его самостоятельно в методе, который фактически использует конкретный репозиторий, например ::

.
using (var context = new DBContext())
{
    IUnitOfWork uow = new UnitOfWork(context);
    ReminderRepository repository = new ReminderRepository(context);
    Reminder remainder = repository.GetReminderByName("...");
    remainder.SomeProperty = "updated value..";
    uow.Save();
}

Единственная цель использования единицы работы состоит в том, чтобы в любом случае иметь возможность совместно использовать один и тот же контекст между несколькими различными хранилищами. Предоставление Dictionary<Type, object> в вашем UnitOfWork ничего не решит, так как цель использования обобщений - обеспечить безопасность типов во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...