Распределение контекста в шаблоне Unit of Work / Repository - PullRequest
0 голосов
/ 23 октября 2018

Здравствуйте! Я реализовал шаблон UoW / Repository в своем приложении, следуя среди прочего Учебникам MSDN.Однако я смущен, когда речь заходит об удалении контекста (что по общему признанию связано с тем фактом, что мне еще многое предстоит узнать об управлении памятью в C #).

В любом случае, у меня есть контекст, который передаетсяна:

  • единица работы
  • универсальные репозитории
  • конкретные репозитории

Мой вопрос: когда именно мне следует распоряжаться этим контекстоми какой из моих интерфейсов должен быть производным от IDisposable / какие классы должны реализовывать IDisposable?

В настоящее время я наследую от IDisposable в IGenericRepository и IUnitOfWork, а затем реализую метод Dispose в GenericRepository и UnitOfWork.Но в руководствах по MSDN реализация метода Dispose находится в определенных репозиториях, а не в общем репозитории, что является причиной моей путаницы.Если я работаю с тем же экземпляром контекста, который передается из базового класса (универсального репозитория) в конкретный репозиторий, который получает контекст с помощью базового конструктора, разве этого будет недостаточно, если я размещу его в универсальном репозитории?

Интерфейсы:

public interface IUnitOfWork : IDisposable
{
    IAccountsRepository Accounts { get; }
    ITransactionsRepository Transactions { get; }
    IAccountGroupsRepository AccountGroups { get; }

    void Complete();
}

public interface IGenericRepository<TEntity> : IDisposable where TEntity : class
{
    void Add(TEntity entity);
    void Edit(TEntity entity);
    IEnumerable<TEntity> GetAll();
    TEntity GetById(object id);
    void Remove(object id);
    void Remove(TEntity entity);
}

public interface IAccountsRepository : IGenericRepository<Account>
{
    IEnumerable<Account> GetForUser(string applicationUserId);
    string GetAccountName(int accountId);
}

Реализация:

public class UnitOfWork : IUnitOfWork
{
    private readonly TinyBooksDbContext _context;
    private bool _disposed;

    public IAccountsRepository Accounts { get; }
    public ITransactionsRepository Transactions { get; }
    public IAccountGroupsRepository AccountGroups { get; set; }


    public UnitOfWork(TinyBooksDbContext context)
    {
        _context = context;
        Accounts = new AccountsRepository(_context);
        Transactions = new TransactionsRepository(_context);
        AccountGroups = new AccountGroupsRepository(_context);
    }

    public void Complete()
    {
        _context.SaveChanges();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    private readonly TinyBooksDbContext _context;
    private readonly DbSet<TEntity> _dbSet;
    private bool _disposed;

    public GenericRepository(TinyBooksDbContext context)
    {
        _context = context;
        _dbSet = _context.Set<TEntity>();

    }

    // C
    public virtual void Add(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    public virtual IEnumerable<TEntity> GetAll()
    {
        return _dbSet.ToList();
    }

    // R
    public virtual TEntity GetById(object id)
    {
        return _dbSet.Find(id);
    }

    // U
    public virtual void Edit(TEntity entity)
    {
        _dbSet.Attach(entity);
        _context.Entry(entity).CurrentValues.SetValues(entity);
    }


    // D
    public virtual void Remove(object id)
    {
        var entity = _dbSet.Find(id);
        Remove(entity);
    }

    public virtual void Remove(TEntity entity)
    {
        if (_context.Entry(entity).State == EntityState.Detached)
            _dbSet.Attach(entity);

        _dbSet.Remove(entity);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

public class AccountsRepository : GenericRepository<Account>, IAccountsRepository
{
    private readonly TinyBooksDbContext _context;
    private bool _disposed;

    public AccountsRepository(TinyBooksDbContext context) : base(context)
    {
        _context = context;
    }

    public IEnumerable<Account> GetForUser(string applicationUserId) =>
        _context.Accounts.Where(a => a.ApplicationUserId == applicationUserId).ToList();

    public string GetAccountName(int accountId) =>
        _context.Accounts.SingleOrDefault(a => a.Id == accountId).Name;
}

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

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

public class UnitOfWork : IDisposable, IUnitOfWork
{
    private readonly TinyBooksDbContext context = new TinyBooksDbContext();

    ......

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Таким образом, ваш контекст будет удален вместе с вашим экземпляром UoW.Вы не должны располагать методами внутри вашего общего репозитория.

0 голосов
/ 23 октября 2018

Вообще говоря, создатель контекста должен им распоряжаться.

Не выбрасывайте контекст в передаваемых вами классах, так как это может сбить с толку других разработчиков, которые могут использовать контекст после его удаления.

В вашем примере репозитории не должны распоряжаться контекстом - им это не принадлежит.

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