refactor: rename domain types and introduce TransactionBehavior pattern

- Rename Template -> EmailTemplate, Provider -> EmailChannel,
  ProviderSettings -> EmailChannelSettings, ProviderType -> EmailChannelType,
  ProviderUsage -> EmailChannelUsage throughout all layers
- Add Undefined = 0 to EmailChannelType enum for safe default handling
- Remove SaveChangesAsync from EfRepository methods — repositories now only stage changes
- Add SaveChangesAsync to IUnitOfWork and EfUnitOfWork
- Add TransactionBehavior MediatR pipeline: wraps every handler in a transaction,
  saves and commits on success, rolls back on exception
- Add MediatR package reference to Services project

Ref: IT-628

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anatolii Grynchuk
2026-05-02 00:16:47 +03:00
parent 088eab0428
commit 6dcc911fc2
28 changed files with 290 additions and 251 deletions
@@ -18,40 +18,28 @@ internal abstract class EfRepository<TEntity>
protected async Task AddAsync(TEntity entity, CancellationToken ct = default)
{
await DbSet.AddAsync(entity, ct);
await DbContext.SaveChangesAsync(ct);
}
protected async Task AddRangeAsync(IEnumerable<TEntity> entities, CancellationToken ct = default)
{
await DbSet.AddRangeAsync(entities, ct);
await DbContext.SaveChangesAsync(ct);
}
protected async Task UpdateAsync(TEntity entity, CancellationToken ct = default)
protected void Update(TEntity entity)
{
DbSet.Update(entity);
await DbContext.SaveChangesAsync(ct);
}
protected async Task DeleteAsync(TEntity entity, CancellationToken ct = default)
protected void Delete(TEntity entity)
{
DbSet.Remove(entity);
await DbContext.SaveChangesAsync(ct);
}
protected async Task DeleteRangeAsync(IEnumerable<TEntity> entities, CancellationToken ct = default)
protected void DeleteRange(IEnumerable<TEntity> entities)
{
DbSet.RemoveRange(entities);
await DbContext.SaveChangesAsync(ct);
}
protected Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken ct = default)
{
return DbSet.AnyAsync(predicate, ct);
}
protected Task SaveAsync(CancellationToken ct = default)
{
return DbContext.SaveChangesAsync(ct);
}
protected Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken ct = default) =>
DbSet.AnyAsync(predicate, ct);
}