diff --git a/SPMS.API/Program.cs b/SPMS.API/Program.cs index 81da982..851b595 100644 --- a/SPMS.API/Program.cs +++ b/SPMS.API/Program.cs @@ -1,6 +1,9 @@ using Microsoft.EntityFrameworkCore; using SPMS.API.Middlewares; +using SPMS.Domain.Interfaces; using SPMS.Infrastructure; +using SPMS.Infrastructure.Persistence; +using SPMS.Infrastructure.Persistence.Repositories; var builder = WebApplication.CreateBuilder(new WebApplicationOptions @@ -17,6 +20,8 @@ var connectionString = builder.Configuration.GetConnectionString("DefaultConnect builder.Services.AddDbContext(options => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))); +builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); +builder.Services.AddScoped(); var app = builder.Build(); diff --git a/SPMS.Infrastructure/Persistence/Repositories/Repository.cs b/SPMS.Infrastructure/Persistence/Repositories/Repository.cs new file mode 100644 index 0000000..1518f8b --- /dev/null +++ b/SPMS.Infrastructure/Persistence/Repositories/Repository.cs @@ -0,0 +1,70 @@ +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; +using SPMS.Domain.Entities; +using SPMS.Domain.Interfaces; + +namespace SPMS.Infrastructure.Persistence.Repositories; + +public class Repository : IRepository where T : BaseEntity +{ + protected readonly AppDbContext _context; + protected readonly DbSet _dbSet; + + public Repository(AppDbContext context) + { + _context = context; + _dbSet = context.Set(); + } + + public async Task GetByIdAsync(long id) + => await _dbSet.FindAsync(id); + + public async Task> GetAllAsync() + => await _dbSet.ToListAsync(); + + public async Task> FindAsync(Expression> predicate) + => await _dbSet.Where(predicate).ToListAsync(); + + public async Task<(IReadOnlyList Items, int TotalCount)> GetPagedAsync( + int page, int size, + Expression>? predicate = null, + Expression>? orderBy = null, + bool descending = true) + { + IQueryable query = _dbSet; + + if (predicate is not null) + query = query.Where(predicate); + + var totalCount = await query.CountAsync(); + + if (orderBy is not null) + query = descending ? query.OrderByDescending(orderBy) : query.OrderBy(orderBy); + else + query = query.OrderByDescending(e => e.Id); + + var items = await query + .Skip((page - 1) * size) + .Take(size) + .ToListAsync(); + + return (items, totalCount); + } + + public async Task CountAsync(Expression>? predicate = null) + => predicate is null + ? await _dbSet.CountAsync() + : await _dbSet.CountAsync(predicate); + + public async Task ExistsAsync(Expression> predicate) + => await _dbSet.AnyAsync(predicate); + + public async Task AddAsync(T entity) + => await _dbSet.AddAsync(entity); + + public void Update(T entity) + => _dbSet.Update(entity); + + public void Delete(T entity) + => _dbSet.Remove(entity); +} diff --git a/SPMS.Infrastructure/Persistence/UnitOfWork.cs b/SPMS.Infrastructure/Persistence/UnitOfWork.cs new file mode 100644 index 0000000..bb606ec --- /dev/null +++ b/SPMS.Infrastructure/Persistence/UnitOfWork.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore.Storage; +using SPMS.Domain.Interfaces; + +namespace SPMS.Infrastructure.Persistence; + +public class UnitOfWork : IUnitOfWork +{ + private readonly AppDbContext _context; + private IDbContextTransaction? _transaction; + + public UnitOfWork(AppDbContext context) + { + _context = context; + } + + public async Task SaveChangesAsync(CancellationToken cancellationToken = default) + => await _context.SaveChangesAsync(cancellationToken); + + public async Task BeginTransactionAsync(CancellationToken cancellationToken = default) + { + _transaction = await _context.Database.BeginTransactionAsync(cancellationToken); + return _transaction; + } + + public async Task CommitTransactionAsync(CancellationToken cancellationToken = default) + { + if (_transaction is null) + throw new InvalidOperationException("Transaction has not been started."); + + await _transaction.CommitAsync(cancellationToken); + await _transaction.DisposeAsync(); + _transaction = null; + } + + public async Task RollbackTransactionAsync(CancellationToken cancellationToken = default) + { + if (_transaction is null) + throw new InvalidOperationException("Transaction has not been started."); + + await _transaction.RollbackAsync(cancellationToken); + await _transaction.DisposeAsync(); + _transaction = null; + } + + public void Dispose() + { + _transaction?.Dispose(); + _context.Dispose(); + } +}