Я реализую приложение ASP. NET MVC, и мне необходимо реализовать шаблон Unit Of Work с репозиториями . Моя реализация разработана следующим образом:
- Объект
UnitOfWork
отвечает за выдачу COMMIT
с и ROLLBACK
с при необходимости. - Объект
UnitOfWork
содержит Transaction
свойство, полученное из внутреннего соединения с БД. Этот объект обеспечивает атомарность операций внутри UnitOfWork
. - . Объект
UnitOfWork
содержит репозитории как свойства, внедренные во время выполнения. - Каждому репозиторию необходимо предоставить объект
IDbTransaction
что UnitOfWork
создано для поддержки атомарности.
Так что теперь я нахожусь в странной ситуации, когда в UnitOfWork
приходится вводить репозитории, которым нужно свойство UnitOfWork
, чтобы быть воплощенным в жизнь. Итак, мой вопрос: как мне это сделать? Или, может быть, что-то в дизайне нужно изменить?
Я сейчас использую SQL Сервер и использую Dapper для вызовов SQL. Кроме того, я думаю об использовании Autofa c в качестве DI-фреймворка.
На данный момент я реализовал UOW и пример репозитория. Код:
IRepository.cs
:
public interface IRepository<TObj, TKey>
{
Task<TObj> DetallesAsync(TKey id);
Task<TKey> AgregarAsync(TObj obj);
}
DbRepository.cs
:
public abstract class DbRepository
{
private readonly IDbConnection _connection;
private readonly IDbTransaction _transaction;
protected IDbConnection Connection
{
get => _connection;
}
protected IDbTransaction Transaction
{
get => _transaction;
}
public DbRepository(IDbTransaction transaction)
{
_transaction = transaction;
_connection = _transaction.Connection;
}
}
RolRepository.cs
:
public class MSSQLRolRepository : DbRepository, IRolRepository
{
public MSSQLRolRepository(IDbTransaction transaction)
: base(transaction)
{
}
public async Task<int> AgregarAsync(Rol obj)
{
var result = await Connection.ExecuteScalarAsync<int>(MSSQLQueries.RolAgregar, param: obj, transaction: Transaction);
return result;
}
public async Task<Rol> DetallesAsync(int id)
{
var param = new { Id = id };
var result = await Connection.QuerySingleOrDefaultAsync<Rol>(MSSQLQueries.RolDetalles, param: param, transaction: Transaction);
return result;
}
public async Task<Rol> DetallesPorNombreAsync(string nombre)
{
var param = new { Nombre = nombre };
var result = await Connection.QuerySingleOrDefaultAsync<Rol>(MSSQLQueries.RolDetallesPorNombre, param: param, transaction: Transaction);
return result;
}
public async Task<Rol[]> ListarAsync(int pagina, int itemsPorPagina)
{
var param = new { Pagina = pagina, ItemsPorPagina = itemsPorPagina };
var result = await Connection.QueryAsync<Rol>(MSSQLQueries.RolListar, param: param, transaction: Transaction);
return result.ToArray();
}
public async Task<Rol[]> ListarTodosAsync()
{
var result = await Connection.QueryAsync<Rol>(MSSQLQueries.RolListar, transaction: Transaction);
return result.ToArray();
}
}
IUnitOfWork.cs
:
public interface IUnitOfWork : IDisposable
{
IDbTransaction Transaction { get; }
IDenunciaRepository DenunciaRepository { get; }
IUsuarioRepository UsuarioRepository { get; }
IRolRepository RolRepository { get; }
void Commit();
void Rollback();
}
MSSQLUnitOfWork.cs
:
public class MSSQLUnitOfWork : IUnitOfWork
{
private bool _already_disposed = false;
private IDbConnection _connection;
private IDbTransaction _transaction;
private IDenunciaRepository _denuncia_repository;
private IUsuarioRepository _usuario_repository;
private IRolRepository _rol_repository;
public IDbTransaction Transaction
{
get => _transaction;
}
public IDenunciaRepository DenunciaRepository
{
get => _denuncia_repository;
}
public IUsuarioRepository UsuarioRepository
{
get => _usuario_repository;
}
public IRolRepository RolRepository
{
get => _rol_repository;
}
public MSSQLUnitOfWork()
{
var connection_string = ConfigurationManager.ConnectionStrings["MSSQL"].ConnectionString;
_connection = new SqlConnection(connection_string);
_connection.Open();
_transaction = _connection.BeginTransaction();
//TODO: Crear repos con transacción
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
_transaction.Rollback();
}
protected virtual void Dispose(bool disposeManagedObjects)
{
if (!_already_disposed)
{
if (disposeManagedObjects)
{
_transaction?.Dispose();
_connection?.Dispose();
}
_already_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}