https://github.com/guilhermebley/catalogocleanarchitecture
Clean Architecture Concepts.
https://github.com/guilhermebley/catalogocleanarchitecture
asp-net-core csharp dapper dapper-donet-core mysql unit-of-work
Last synced: 2 months ago
JSON representation
Clean Architecture Concepts.
- Host: GitHub
- URL: https://github.com/guilhermebley/catalogocleanarchitecture
- Owner: GuilhermeBley
- Created: 2022-08-09T02:08:39.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2022-08-23T23:08:39.000Z (almost 4 years ago)
- Last Synced: 2025-03-04T07:30:19.166Z (over 1 year ago)
- Topics: asp-net-core, csharp, dapper, dapper-donet-core, mysql, unit-of-work
- Language: C#
- Homepage:
- Size: 59.6 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Catalogo
## CLEAN ARCHITECTURE
- ASP NET
- Solution with clean architecture
- Use Dapper
- Unit Of Work
## Unit Of Work With Dapper
The objective is make a Unit Of Work, which can execute a `SaveChanges` from various Repositories, persistency the data.
With the Dependency Injection is managed a shared connection on the repositories.
In Catalogo.CrossCutting.IoC we could see this:
```C#
services
.AddSingleton(configuration)
.AddTransient()
.AddScoped()
.AddScoped()
.AddScoped()
.AddScoped()
// UoW
.AddScoped()
.AddScoped(x => x.GetRequiredService())
.AddScoped(x => x.GetRequiredService());
```
The persistence of data execution is make in `Catalogo.Application.UoW.IUnitOfWork`, which have delivered to Services.
The connection to access the data was inserted in the interface `Catalogo.Infrastructure.Context.UnitOfWork.Repository`, which is shared to Repositories.
```C#
namespace Catalogo.Infrastructure.Context
{
///
/// Give a shared connection to repositorys
///
public interface IUnitOfWorkRepository : IUnitOfWork
{
///
/// Avaliable connection
///
IDbConnection Connection { get; }
///
/// Avaliable Transaction
///
IDbTransaction Transaction { get; }
}
}
namespace Catalogo.Application.UoW
{
///
/// Unit of work give a shared transactions to repositorys
///
public interface IUnitOfWork : IDisposable
{
///
/// Identifier of unit
///
Guid Identifier { get; }
///
/// Necessary to create and open a new connection
///
/// async result of opened
Task OpenConnectionAsync();
///
/// Creates a connection (if method haven't executed) and transaction
///
///
/// Starts a transaction to the repositorys
/// Use > after execute
///
/// async result of opened
Task BeginTransactionAsync();
///
/// Commits if is ok or roll back if throw a exception
///
/// async
Task SaveChangesAsync();
}
}
```
And a unique class implements a both (namespace `Catalogo.Infrastructure.Context`).
```C#
///
/// Manage connections and transactions
///
public class UnitOfWorkRepository : IUnitOfWorkRepository
{
private DbConnection _connection { get; set; }
public DbTransaction _transaction { get; set; }
public IDbConnection Connection => _connection ?? throw new DataException("Connection is closed.");
public IDbTransaction Transaction => _transaction;
public Guid Identifier { get; } = Guid.NewGuid();
private readonly IConnectionFactory _connectionFactory;
public UnitOfWorkRepository(IConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task BeginTransactionAsync()
{
await OpenConnectionAsync();
if (_transaction is null)
_transaction = await _connection.BeginTransactionAsync();
return this;
}
public async Task SaveChangesAsync()
{
try
{
await _transaction?.CommitAsync();
}
catch
{
await _transaction?.RollbackAsync();
throw;
}
finally
{
_transaction?.Dispose();
_transaction = null;
}
}
public void Dispose()
{
if (_transaction is not null)
{
_transaction.Dispose();
_transaction = null;
}
if (_connection is not null)
{
_connection.Dispose();
_connection = null;
}
}
public async Task OpenConnectionAsync()
{
if (_connection is null)
{
_connection = _connectionFactory.CreateConn();
await _connection.OpenAsync();
}
return this;
}
}
```
To use this implementation two parts needed.
- Repository
Needs a connection and transaction to execute the commands, and in all of the connections in DataBase should be use this way:
```C#
[...]
public class CategoriaRepository : RepositoryBase, ICategoriaRepository
{
private readonly IUnitOfWorkRepository _uoW;
///
/// Connection to execute commands and querys
///
protected IDbConnection _connection => _uoW.Connection;
///
/// Shared execution
///
protected IDbTransaction _transaction => _uoW.Transaction;
public RepositoryBase(IUnitOfWorkRepository uoW)
{
_uoW = uoW;
}
public async Task CreateAsync(Produto product)
{
return
await _connection.ExecuteAsync(
"INSERT INTO catalagodapper.produto (Nome, Descricao, Preco, ImagemUrl, Estoque, DataCadastro, IdCategoria) VALUES (@Nome, @Descricao, @Preco, @ImagemUrl, @Estoque, @DataCadastro, @IdCategoria);",
product,
_transaction
);
}
}
[...]
```
- Services
The Services manage a open connection to Repositories, having two ways, the simple execution, without transaction, or with it.
```C#
public class CategoriaService : ICategoriaService
{
private readonly IUnitOfWork _uow;
private ICategoriaRepository _categoryRepository;
private readonly IMapper _mapper;
public CategoriaService(
IUnitOfWork uow,
ICategoriaRepository categoryRepository,
IMapper mapper)
{
_uow = uow;
_categoryRepository = categoryRepository;
_mapper = mapper;
}
public async Task Add(CategoriaDTO categoryDto)
{
var categoryEntity = _mapper.Map(categoryDto);
categoryEntity.Validate();
using (await _uow.BeginTransactionAsync())
{
if ((await _categoryRepository.GetByName(categoryEntity.Nome)) is not null)
throw new ConflictException($"Category with name {categoryEntity.Nome} already exists.");
await _categoryRepository.CreateAsync(categoryEntity);
await _uow.SaveChangesAsync();
}
}
}
```