From 45a7086c9ae8bf87a683a60460b8954264306c00 Mon Sep 17 00:00:00 2001 From: TekH Date: Mon, 3 Aug 2026 12:07:09 +0200 Subject: [PATCH] Refactor repository pattern and modernize codebase Removed `SaveChangesAsync` from `IRepository` and `Repository` to centralize transaction management in `DbContext`. Updated `CfgProfileRepository` to use `Context` property instead of `_context`. Refactored `Repository` class to use C# 9.0 record-like constructor syntax and replaced private fields with properties (`Context`, `DbSet`, `Mapper`). Replaced `Any()` with `Count == 0` for null checks and updated `FindAsync` to use C# 11 object array syntax. Added conditional compilation for framework-specific differences. These changes improve readability, consistency, and leverage modern C# features. --- ECMJobRunner.Domain/Interfaces/IRepository.cs | 5 - .../Repositories/CfgProfileRepository.cs | 4 +- .../Repositories/Repository.cs | 115 ++++++++---------- 3 files changed, 54 insertions(+), 70 deletions(-) diff --git a/ECMJobRunner.Domain/Interfaces/IRepository.cs b/ECMJobRunner.Domain/Interfaces/IRepository.cs index 204414d..d19cb92 100644 --- a/ECMJobRunner.Domain/Interfaces/IRepository.cs +++ b/ECMJobRunner.Domain/Interfaces/IRepository.cs @@ -90,10 +90,5 @@ namespace ECMJobRunner.Domain.Interfaces /// Cancellation token /// True if entity was found and deleted, false otherwise Task DeleteSingleAsync(Expression> predicate, CancellationToken cancellationToken = default); - - /// - /// Save all changes asynchronously - /// - Task SaveChangesAsync(CancellationToken cancellationToken = default); } } diff --git a/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs b/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs index af69dfd..32a0585 100644 --- a/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs +++ b/ECMJobRunner.Infrastructure/Repositories/CfgProfileRepository.cs @@ -31,7 +31,7 @@ namespace ECMJobRunner.Infrastructure.Repositories /// public async Task GetByIdWithSqlJobsAsync(long id, CancellationToken cancellationToken = default) { - return await _context.CfgProfiles + return await Context.CfgProfiles .Include(p => p.SqlJobs) .FirstOrDefaultAsync(p => p.Id == id, cancellationToken); } @@ -41,7 +41,7 @@ namespace ECMJobRunner.Infrastructure.Repositories /// public async Task> GetAllActiveWithSqlJobsAsync(CancellationToken cancellationToken = default) { - return await _context.CfgProfiles + return await Context.CfgProfiles .Include(p => p.SqlJobs) .Where(p => p.Active) .ToListAsync(cancellationToken); diff --git a/ECMJobRunner.Infrastructure/Repositories/Repository.cs b/ECMJobRunner.Infrastructure/Repositories/Repository.cs index e747531..5c1f9b1 100644 --- a/ECMJobRunner.Infrastructure/Repositories/Repository.cs +++ b/ECMJobRunner.Infrastructure/Repositories/Repository.cs @@ -20,145 +20,144 @@ namespace ECMJobRunner.Infrastructure.Repositories /// Uses AutoMapper for DTO mapping /// /// Entity type - public class Repository : IRepository where TEntity : class + /// + /// Constructor + /// + public class Repository(JobRunnerDbContext context, IMapper mapper) : IRepository where TEntity : class { /// /// Database context /// - protected readonly JobRunnerDbContext _context; + protected readonly JobRunnerDbContext Context = context ?? throw new ArgumentNullException(nameof(context)); /// /// DbSet for the entity /// - protected readonly DbSet _dbSet; + protected readonly DbSet DbSet = context.Set(); /// /// AutoMapper instance for DTO mapping /// - protected readonly IMapper _mapper; - - /// - /// Constructor - /// - public Repository(JobRunnerDbContext context, IMapper mapper) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - _dbSet = context.Set(); - } + protected readonly IMapper Mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); /// public virtual async Task GetByIdAsync(long id, CancellationToken cancellationToken = default) { #if NET48 - return await _dbSet.FindAsync(cancellationToken, id); + return await DbSet.FindAsync(cancellationToken, id); #else - return await _dbSet.FindAsync(new object[] { id }, cancellationToken); + return await DbSet.FindAsync([id], cancellationToken); #endif } /// public virtual async Task> GetAllAsync(CancellationToken cancellationToken = default) { - return await _dbSet.ToListAsync(cancellationToken); + return await DbSet.ToListAsync(cancellationToken); } /// public virtual async Task> FindAsync(Expression> predicate, CancellationToken cancellationToken = default) { - return await _dbSet.Where(predicate).ToListAsync(cancellationToken); + return await DbSet.Where(predicate).ToListAsync(cancellationToken); } /// public virtual async Task SingleOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default) { - return await _dbSet.SingleOrDefaultAsync(predicate, cancellationToken); + return await DbSet.SingleOrDefaultAsync(predicate, cancellationToken); } /// public virtual async Task AddAsync(TDto dto, CancellationToken cancellationToken = default) where TDto : class { +#if NETFRAMEWORK if (dto == null) throw new ArgumentNullException(nameof(dto)); - - var entity = _mapper.Map(dto); - -#if NET48 - _dbSet.Add(entity); - await Task.CompletedTask; -#else - await _dbSet.AddAsync(entity, cancellationToken); #endif - await SaveChangesAsync(cancellationToken); + var entity = Mapper.Map(dto); + +#if NET48 + DbSet.Add(entity); +#else + await DbSet.AddAsync(entity, cancellationToken); +#endif + + await Context.SaveChangesAsync(cancellationToken); return entity; } /// public virtual async Task AddRangeAsync(IEnumerable dtos, CancellationToken cancellationToken = default) where TDto : class { +#if NETFRAMEWORK if (dtos == null) throw new ArgumentNullException(nameof(dtos)); - - var dtoList = dtos.ToList(); - if (!dtoList.Any()) - return 0; - - var entities = _mapper.Map>(dtoList); - -#if NET48 - _dbSet.AddRange(entities); - await Task.CompletedTask; -#else - await _dbSet.AddRangeAsync(entities, cancellationToken); #endif - return await SaveChangesAsync(cancellationToken); + var dtoList = dtos.ToList(); + if (dtoList.Count == 0) + return 0; + + var entities = Mapper.Map>(dtoList); + +#if NET48 + DbSet.AddRange(entities); +#else + await DbSet.AddRangeAsync(entities, cancellationToken); +#endif + + return await Context.SaveChangesAsync(cancellationToken); } /// public virtual async Task UpdateAsync(Expression> predicate, TDto dto, CancellationToken cancellationToken = default) where TDto : class { +#if NETFRAMEWORK if (dto == null) throw new ArgumentNullException(nameof(dto)); +#endif - var entities = await _dbSet.Where(predicate).ToListAsync(cancellationToken); + var entities = await DbSet.Where(predicate).ToListAsync(cancellationToken); - if (!entities.Any()) + if (entities.Count == 0) return 0; foreach (var entity in entities) { - _mapper.Map(dto, entity); + Mapper.Map(dto, entity); } - return await SaveChangesAsync(cancellationToken); + return await Context.SaveChangesAsync(cancellationToken); } /// public virtual async Task UpdateSingleAsync(Expression> predicate, TDto dto, CancellationToken cancellationToken = default) where TDto : class { +#if NETFRAMEWORK if (dto == null) throw new ArgumentNullException(nameof(dto)); +#endif var entity = await SingleOrDefaultAsync(predicate, cancellationToken); if (entity == null) return false; - _mapper.Map(dto, entity); + Mapper.Map(dto, entity); - await SaveChangesAsync(cancellationToken); + await Context.SaveChangesAsync(cancellationToken); return true; } /// public virtual async Task DeleteAsync(Expression> predicate, CancellationToken cancellationToken = default) { - var entities = await _dbSet.Where(predicate).ToListAsync(cancellationToken); + var entities = await DbSet.Where(predicate).ToListAsync(cancellationToken); - if (!entities.Any()) + if (entities.Count == 0) return 0; - _dbSet.RemoveRange(entities); + DbSet.RemoveRange(entities); - return await SaveChangesAsync(cancellationToken); + return await Context.SaveChangesAsync(cancellationToken); } /// @@ -169,20 +168,10 @@ namespace ECMJobRunner.Infrastructure.Repositories if (entity == null) return false; - _dbSet.Remove(entity); + DbSet.Remove(entity); - await SaveChangesAsync(cancellationToken); + await Context.SaveChangesAsync(cancellationToken); return true; } - - /// - public virtual async Task SaveChangesAsync(CancellationToken cancellationToken = default) - { -#if NET48 - return await _context.SaveChangesAsync(); -#else - return await _context.SaveChangesAsync(cancellationToken); -#endif - } } }