From 5d5d091dbe64f684a968dbf9b1b940dfc5e2f0b4 Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Fri, 24 Oct 2025 00:44:53 +0300 Subject: [PATCH] Refactors repositories for improved structure Improves repository structure by introducing a generic DbCrud class and dedicated repositories for each entity. This change enhances code maintainability and testability by separating concerns. It also introduces soft delete functionality to the generic repository. --- .../Authentication/Requests/LoginRequest.cs | 7 +- .../Repositories/IMissionRepository.cs | 4 +- .../Interfaces/Repositories/IRepository.cs | 22 ++++-- .../Authentication/AuthenticationService.cs | 2 +- .../Services/Missions/MissionService.cs | 4 +- .../Domain/Services/Submits/SubmitService.cs | 2 +- .../Database/Repositories/DbCrud.cs | 70 +++++++++++++++++++ .../Repositories/MissionRepository.cs | 59 +++++++++------- .../Database/Repositories/Repository.cs | 43 +++++++++--- .../Database/Repositories/SubmitRepository.cs | 43 ++++++++++-- .../Database/Repositories/UserRepository.cs | 49 ++++++++++--- 11 files changed, 242 insertions(+), 63 deletions(-) create mode 100644 LiquidCode/Infrastructure/Database/Repositories/DbCrud.cs diff --git a/LiquidCode/Api/Authentication/Requests/LoginRequest.cs b/LiquidCode/Api/Authentication/Requests/LoginRequest.cs index fb0b697..ae5bb14 100644 --- a/LiquidCode/Api/Authentication/Requests/LoginRequest.cs +++ b/LiquidCode/Api/Authentication/Requests/LoginRequest.cs @@ -3,4 +3,9 @@ namespace LiquidCode.Api.Authentication.Requests; /// /// Модель запроса для входа пользователя /// -public record LoginRequest(string Username, string Password); +/// Имя пользователя +/// Пароль +public record LoginRequest( + string Username, + string Password + ); diff --git a/LiquidCode/Domain/Interfaces/Repositories/IMissionRepository.cs b/LiquidCode/Domain/Interfaces/Repositories/IMissionRepository.cs index 0f74012..2bcafb6 100644 --- a/LiquidCode/Domain/Interfaces/Repositories/IMissionRepository.cs +++ b/LiquidCode/Domain/Interfaces/Repositories/IMissionRepository.cs @@ -35,12 +35,12 @@ public interface IMissionRepository : IRepository /// /// Добавляет текстовые данные миссии /// - Task AddMissionTextAsync(DbMissionPublicTextData textData, CancellationToken cancellationToken = default); + Task CreateMissionTextAsync(DbMissionPublicTextData textData, CancellationToken cancellationToken = default); /// /// Добавляет несколько записей текстовых данных миссии /// - Task AddMissionTextsAsync(IEnumerable textData, CancellationToken cancellationToken = default); + Task CreateMissionTextsAsync(IEnumerable textData, CancellationToken cancellationToken = default); /// /// Подсчитывает общее количество миссий diff --git a/LiquidCode/Domain/Interfaces/Repositories/IRepository.cs b/LiquidCode/Domain/Interfaces/Repositories/IRepository.cs index fbc48ad..3602ba5 100644 --- a/LiquidCode/Domain/Interfaces/Repositories/IRepository.cs +++ b/LiquidCode/Domain/Interfaces/Repositories/IRepository.cs @@ -1,10 +1,12 @@ +using LiquidCode.Infrastructure.Database.Entities; + namespace LiquidCode.Domain.Interfaces.Repositories; /// /// Базовый интерфейс репозитория для общих операций CRUD /// /// Тип сущности, управляемой этим репозиторием -public interface IRepository where TEntity : class +public interface IRepository where TEntity : class, ISoftDeletable { /// /// Находит сущность по ее ID @@ -12,14 +14,19 @@ public interface IRepository where TEntity : class Task FindByIdAsync(int id, CancellationToken cancellationToken = default); /// - /// Получает все сущности + /// Получает все сущности с пагинацией /// - Task> GetAllAsync(CancellationToken cancellationToken = default); + /// Количество элементов на странице + /// Номер страницы (начиная с 0) + /// Токен отмены + /// Кортеж (сущности, естьСледующаяСтраница) + Task<(IEnumerable Items, bool HasNextPage)> GetPageAsync( + int pageSize, int pageNumber, CancellationToken cancellationToken = default); /// /// Добавляет новую сущность /// - Task AddAsync(TEntity entity, CancellationToken cancellationToken = default); + Task CreateAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Обновляет существующую сущность @@ -29,7 +36,12 @@ public interface IRepository where TEntity : class /// /// Удаляет сущность /// - Task RemoveAsync(TEntity entity, CancellationToken cancellationToken = default); + Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); + + /// + /// Мягко удаляет сущность + /// + Task SoftDeleteAsync(TEntity entity, CancellationToken cancellationToken = default); /// /// Сохраняет все изменения, сделанные в базе данных diff --git a/LiquidCode/Domain/Services/Authentication/AuthenticationService.cs b/LiquidCode/Domain/Services/Authentication/AuthenticationService.cs index 0b3dd7b..f3e30e4 100644 --- a/LiquidCode/Domain/Services/Authentication/AuthenticationService.cs +++ b/LiquidCode/Domain/Services/Authentication/AuthenticationService.cs @@ -55,7 +55,7 @@ public class AuthenticationService : IAuthenticationService Salt = "" // BCrypt управляет солью внутренне }; - await _userRepository.AddAsync(newUser, cancellationToken); + await _userRepository.CreateAsync(newUser, cancellationToken); _logger.LogInformation("User registered successfully: {Username}", request.Username); // Автоматически войти пользователю diff --git a/LiquidCode/Domain/Services/Missions/MissionService.cs b/LiquidCode/Domain/Services/Missions/MissionService.cs index 4d98e93..a0312cf 100644 --- a/LiquidCode/Domain/Services/Missions/MissionService.cs +++ b/LiquidCode/Domain/Services/Missions/MissionService.cs @@ -83,7 +83,7 @@ public class MissionService : IMissionService UpdatedAt = DateTime.UtcNow }; - await _missionRepository.AddAsync(dbMission, cancellationToken); + await _missionRepository.CreateAsync(dbMission, cancellationToken); // Распарсить и сохранить текстовые данные миссии var missionTexts = ExtractMissionTexts(statementSectionsPath, dbMission.Id); @@ -104,7 +104,7 @@ public class MissionService : IMissionService } // Добавить текстовые данные миссии в базу данных - await _missionRepository.AddMissionTextsAsync(missionTexts, cancellationToken); + await _missionRepository.CreateMissionTextsAsync(missionTexts, cancellationToken); await _missionRepository.SaveChangesAsync(cancellationToken); _logger.LogInformation("Mission uploaded successfully: {MissionId}", dbMission.Id); diff --git a/LiquidCode/Domain/Services/Submits/SubmitService.cs b/LiquidCode/Domain/Services/Submits/SubmitService.cs index 72feed2..6a13002 100644 --- a/LiquidCode/Domain/Services/Submits/SubmitService.cs +++ b/LiquidCode/Domain/Services/Submits/SubmitService.cs @@ -72,7 +72,7 @@ public class SubmitService : ISubmitService Solution = solution }; - await _submitRepository.AddAsync(submission, cancellationToken); + await _submitRepository.CreateAsync(submission, cancellationToken); _logger.LogInformation("Solution submitted: UserId={UserId}, MissionId={MissionId}, SolutionId={SolutionId}", userId, missionId, solution.Id); return solution; diff --git a/LiquidCode/Infrastructure/Database/Repositories/DbCrud.cs b/LiquidCode/Infrastructure/Database/Repositories/DbCrud.cs new file mode 100644 index 0000000..ecc0bc2 --- /dev/null +++ b/LiquidCode/Infrastructure/Database/Repositories/DbCrud.cs @@ -0,0 +1,70 @@ +using LiquidCode.Domain.Interfaces.Repositories; +using LiquidCode.Infrastructure.Database; +using LiquidCode.Infrastructure.Database.Entities; +using Microsoft.EntityFrameworkCore; + +namespace LiquidCode.Infrastructure.Database.Repositories; + +/// +/// Базовая реализация репозитория, предоставляющая общие операции CRUD +/// +public class DbCrud : IRepository where TEntity : class, ISoftDeletable +{ + private readonly LiquidDbContext _dbContext; + public readonly DbSet DbSet; + + public DbCrud(LiquidDbContext dbContext) + { + _dbContext = dbContext; + DbSet = dbContext.Set(); + } + + public virtual async Task FindByIdAsync(int id, CancellationToken cancellationToken = default) => + await DbSet.FindAsync(new object?[] { id }, cancellationToken); + + public virtual async Task<(IEnumerable Items, bool HasNextPage)> GetPageAsync( + int pageSize, int pageNumber, CancellationToken cancellationToken = default) + { + if (pageSize <= 0 || pageNumber < 0) + throw new ArgumentException("Page size must be positive, page number must be non-negative"); + + var totalCount = await DbSet.CountAsync(cancellationToken); + var hasNextPage = totalCount > pageSize * (pageNumber + 1); + + var items = await DbSet + .OrderBy(x => EF.Property(x, "Id")) + .Skip(pageSize * pageNumber) + .Take(pageSize) + .ToListAsync(cancellationToken); + + return (items, hasNextPage); + } + + public virtual async Task CreateAsync(TEntity entity, CancellationToken cancellationToken = default) + { + await DbSet.AddAsync(entity, cancellationToken); + await SaveChangesAsync(cancellationToken); + } + + public virtual async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) + { + DbSet.Update(entity); + await SaveChangesAsync(cancellationToken); + } + + public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + { + DbSet.Remove(entity); + await SaveChangesAsync(cancellationToken); + } + + public virtual async Task SoftDeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + { + entity.IsDeleted = true; + DbSet.Update(entity); + await SaveChangesAsync(cancellationToken); + } + + public async Task SaveChangesAsync(CancellationToken cancellationToken = default) => + await _dbContext.SaveChangesAsync(cancellationToken); +} diff --git a/LiquidCode/Infrastructure/Database/Repositories/MissionRepository.cs b/LiquidCode/Infrastructure/Database/Repositories/MissionRepository.cs index 0f86b7e..b6313dd 100644 --- a/LiquidCode/Infrastructure/Database/Repositories/MissionRepository.cs +++ b/LiquidCode/Infrastructure/Database/Repositories/MissionRepository.cs @@ -8,52 +8,63 @@ namespace LiquidCode.Infrastructure.Database.Repositories; /// /// Реализация репозитория для операций с базой данных, связанных с миссиями /// -public class MissionRepository : Repository, IMissionRepository +public class MissionRepository : IMissionRepository { - public MissionRepository(LiquidDbContext dbContext) : base(dbContext) + private readonly LiquidDbContext _dbContext; + private readonly DbCrud _missionRepository; + + public MissionRepository(LiquidDbContext dbContext) { + _dbContext = dbContext; + _missionRepository = new DbCrud(dbContext); } - public async Task<(IEnumerable Missions, bool HasNextPage)> GetMissionsPageAsync( - int pageSize, int pageNumber, CancellationToken cancellationToken = default) - { - if (pageSize <= 0 || pageNumber < 0) - throw new ArgumentException("Page size must be positive, page number must be non-negative"); + // IRepository implementation (delegated to _missionRepository) + public Task FindByIdAsync(int id, CancellationToken cancellationToken = default) => + _missionRepository.FindByIdAsync(id, cancellationToken); - var totalCount = await DbSet.CountAsync(cancellationToken); - var hasNextPage = totalCount > pageSize * (pageNumber + 1); + public Task<(IEnumerable Items, bool HasNextPage)> GetPageAsync( + int pageSize, int pageNumber, CancellationToken cancellationToken = default) => + _missionRepository.GetPageAsync(pageSize, pageNumber, cancellationToken); - var missions = await DbSet - .OrderBy(m => m.Id) - .Skip(pageSize * pageNumber) - .Take(pageSize) - .ToListAsync(cancellationToken); + public Task CreateAsync(DbMission entity, CancellationToken cancellationToken = default) => + _missionRepository.CreateAsync(entity, cancellationToken); - return (missions, hasNextPage); - } + public Task UpdateAsync(DbMission entity, CancellationToken cancellationToken = default) => + _missionRepository.UpdateAsync(entity, cancellationToken); + public Task DeleteAsync(DbMission entity, CancellationToken cancellationToken = default) => + _missionRepository.DeleteAsync(entity, cancellationToken); + + public Task SoftDeleteAsync(DbMission entity, CancellationToken cancellationToken = default) => + _missionRepository.SoftDeleteAsync(entity, cancellationToken); + + public Task SaveChangesAsync(CancellationToken cancellationToken = default) => + _missionRepository.SaveChangesAsync(cancellationToken); + + // IMissionRepository specific methods public async Task> GetMissionsByAuthorAsync(int authorId, CancellationToken cancellationToken = default) => - await DbSet + await _dbContext.Set() .Where(m => m.Author.Id == authorId) .OrderByDescending(m => m.CreatedAt) .ToListAsync(cancellationToken); public async Task GetMissionTextAsync(int missionId, string language, CancellationToken cancellationToken = default) => - await DbContext.MissionsTextData + await _dbContext.MissionsTextData .FirstOrDefaultAsync(m => m.MissionId == missionId && m.Language == language, cancellationToken); public async Task> GetMissionLanguagesAsync(int missionId, CancellationToken cancellationToken = default) => - await DbContext.MissionsTextData + await _dbContext.MissionsTextData .Where(m => m.MissionId == missionId) .Select(m => m.Language) .ToListAsync(cancellationToken); - public async Task AddMissionTextAsync(DbMissionPublicTextData textData, CancellationToken cancellationToken = default) => - await DbContext.MissionsTextData.AddAsync(textData, cancellationToken); + public async Task CreateMissionTextAsync(DbMissionPublicTextData textData, CancellationToken cancellationToken = default) => + await _dbContext.MissionsTextData.AddAsync(textData, cancellationToken); - public async Task AddMissionTextsAsync(IEnumerable textData, CancellationToken cancellationToken = default) => - await DbContext.MissionsTextData.AddRangeAsync(textData, cancellationToken); + public async Task CreateMissionTextsAsync(IEnumerable textData, CancellationToken cancellationToken = default) => + await _dbContext.MissionsTextData.AddRangeAsync(textData, cancellationToken); public async Task CountMissionsAsync(CancellationToken cancellationToken = default) => - await DbSet.CountAsync(cancellationToken); + await _dbContext.Set().CountAsync(cancellationToken); } diff --git a/LiquidCode/Infrastructure/Database/Repositories/Repository.cs b/LiquidCode/Infrastructure/Database/Repositories/Repository.cs index 510443f..ecc0bc2 100644 --- a/LiquidCode/Infrastructure/Database/Repositories/Repository.cs +++ b/LiquidCode/Infrastructure/Database/Repositories/Repository.cs @@ -1,5 +1,6 @@ using LiquidCode.Domain.Interfaces.Repositories; using LiquidCode.Infrastructure.Database; +using LiquidCode.Infrastructure.Database.Entities; using Microsoft.EntityFrameworkCore; namespace LiquidCode.Infrastructure.Database.Repositories; @@ -7,24 +8,39 @@ namespace LiquidCode.Infrastructure.Database.Repositories; /// /// Базовая реализация репозитория, предоставляющая общие операции CRUD /// -public class Repository : IRepository where TEntity : class +public class DbCrud : IRepository where TEntity : class, ISoftDeletable { - protected readonly LiquidDbContext DbContext; - protected readonly DbSet DbSet; + private readonly LiquidDbContext _dbContext; + public readonly DbSet DbSet; - public Repository(LiquidDbContext dbContext) + public DbCrud(LiquidDbContext dbContext) { - DbContext = dbContext; + _dbContext = dbContext; DbSet = dbContext.Set(); } public virtual async Task FindByIdAsync(int id, CancellationToken cancellationToken = default) => await DbSet.FindAsync(new object?[] { id }, cancellationToken); - public virtual async Task> GetAllAsync(CancellationToken cancellationToken = default) => - await DbSet.ToListAsync(cancellationToken); + public virtual async Task<(IEnumerable Items, bool HasNextPage)> GetPageAsync( + int pageSize, int pageNumber, CancellationToken cancellationToken = default) + { + if (pageSize <= 0 || pageNumber < 0) + throw new ArgumentException("Page size must be positive, page number must be non-negative"); - public virtual async Task AddAsync(TEntity entity, CancellationToken cancellationToken = default) + var totalCount = await DbSet.CountAsync(cancellationToken); + var hasNextPage = totalCount > pageSize * (pageNumber + 1); + + var items = await DbSet + .OrderBy(x => EF.Property(x, "Id")) + .Skip(pageSize * pageNumber) + .Take(pageSize) + .ToListAsync(cancellationToken); + + return (items, hasNextPage); + } + + public virtual async Task CreateAsync(TEntity entity, CancellationToken cancellationToken = default) { await DbSet.AddAsync(entity, cancellationToken); await SaveChangesAsync(cancellationToken); @@ -36,12 +52,19 @@ public class Repository : IRepository where TEntity : class await SaveChangesAsync(cancellationToken); } - public virtual async Task RemoveAsync(TEntity entity, CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) { DbSet.Remove(entity); await SaveChangesAsync(cancellationToken); } + public virtual async Task SoftDeleteAsync(TEntity entity, CancellationToken cancellationToken = default) + { + entity.IsDeleted = true; + DbSet.Update(entity); + await SaveChangesAsync(cancellationToken); + } + public async Task SaveChangesAsync(CancellationToken cancellationToken = default) => - await DbContext.SaveChangesAsync(cancellationToken); + await _dbContext.SaveChangesAsync(cancellationToken); } diff --git a/LiquidCode/Infrastructure/Database/Repositories/SubmitRepository.cs b/LiquidCode/Infrastructure/Database/Repositories/SubmitRepository.cs index ac92308..c318ba2 100644 --- a/LiquidCode/Infrastructure/Database/Repositories/SubmitRepository.cs +++ b/LiquidCode/Infrastructure/Database/Repositories/SubmitRepository.cs @@ -8,34 +8,63 @@ namespace LiquidCode.Infrastructure.Database.Repositories; /// /// Реализация репозитория для операций с базой данных, связанных с отправками пользователей /// -public class SubmitRepository : Repository, ISubmitRepository +public class SubmitRepository : ISubmitRepository { - public SubmitRepository(LiquidDbContext dbContext) : base(dbContext) + private readonly LiquidDbContext _dbContext; + private readonly DbCrud _submitRepository; + + public SubmitRepository(LiquidDbContext dbContext) { + _dbContext = dbContext; + _submitRepository = new DbCrud(dbContext); } + // IRepository implementation (delegated to _submitRepository) + public Task FindByIdAsync(int id, CancellationToken cancellationToken = default) => + _submitRepository.FindByIdAsync(id, cancellationToken); + + public Task<(IEnumerable Items, bool HasNextPage)> GetPageAsync( + int pageSize, int pageNumber, CancellationToken cancellationToken = default) => + _submitRepository.GetPageAsync(pageSize, pageNumber, cancellationToken); + + public Task CreateAsync(DbUserSubmit entity, CancellationToken cancellationToken = default) => + _submitRepository.CreateAsync(entity, cancellationToken); + + public Task UpdateAsync(DbUserSubmit entity, CancellationToken cancellationToken = default) => + _submitRepository.UpdateAsync(entity, cancellationToken); + + public Task DeleteAsync(DbUserSubmit entity, CancellationToken cancellationToken = default) => + _submitRepository.DeleteAsync(entity, cancellationToken); + + public Task SoftDeleteAsync(DbUserSubmit entity, CancellationToken cancellationToken = default) => + _submitRepository.SoftDeleteAsync(entity, cancellationToken); + + public Task SaveChangesAsync(CancellationToken cancellationToken = default) => + _submitRepository.SaveChangesAsync(cancellationToken); + + // ISubmitRepository specific methods public async Task> GetSubmissionsByUserAsync(int userId, CancellationToken cancellationToken = default) => - await DbSet + await _dbContext.Set() .Where(s => s.User.Id == userId) .OrderByDescending(s => s.Solution!.Time) .ToListAsync(cancellationToken); public async Task> GetSubmissionsByMissionAsync(int missionId, CancellationToken cancellationToken = default) => - await DbSet + await _dbContext.Set() .Where(s => s.Solution!.Mission.Id == missionId) .OrderByDescending(s => s.Solution!.Time) .ToListAsync(cancellationToken); public async Task GetSubmissionWithDetailsAsync(int submissionId, CancellationToken cancellationToken = default) => - await DbSet + await _dbContext.Set() .Include(s => s.User) .Include(s => s.Solution) .FirstOrDefaultAsync(s => s.Id == submissionId, cancellationToken); public async Task GetSolutionAsync(int solutionId, CancellationToken cancellationToken = default) => - await DbContext.Solutions + await _dbContext.Solutions .FirstOrDefaultAsync(s => s.Id == solutionId, cancellationToken); public async Task AddSolutionAsync(DbSolution solution, CancellationToken cancellationToken = default) => - await DbContext.Solutions.AddAsync(solution, cancellationToken); + await _dbContext.Solutions.AddAsync(solution, cancellationToken); } diff --git a/LiquidCode/Infrastructure/Database/Repositories/UserRepository.cs b/LiquidCode/Infrastructure/Database/Repositories/UserRepository.cs index 1bf011d..45dd48d 100644 --- a/LiquidCode/Infrastructure/Database/Repositories/UserRepository.cs +++ b/LiquidCode/Infrastructure/Database/Repositories/UserRepository.cs @@ -8,39 +8,68 @@ namespace LiquidCode.Infrastructure.Database.Repositories; /// /// Реализация репозитория для операций с базой данных, связанных с пользователями /// -public class UserRepository : Repository, IUserRepository +public class UserRepository : IUserRepository { - public UserRepository(LiquidDbContext dbContext) : base(dbContext) + private readonly LiquidDbContext _dbContext; + private readonly DbCrud _userRepository; + + public UserRepository(LiquidDbContext dbContext) { + _dbContext = dbContext; + _userRepository = new DbCrud(dbContext); } + // IRepository implementation (delegated to _userRepository) + public Task FindByIdAsync(int id, CancellationToken cancellationToken = default) => + _userRepository.FindByIdAsync(id, cancellationToken); + + public Task<(IEnumerable Items, bool HasNextPage)> GetPageAsync( + int pageSize, int pageNumber, CancellationToken cancellationToken = default) => + _userRepository.GetPageAsync(pageSize, pageNumber, cancellationToken); + + public Task CreateAsync(DbUser entity, CancellationToken cancellationToken = default) => + _userRepository.CreateAsync(entity, cancellationToken); + + public Task UpdateAsync(DbUser entity, CancellationToken cancellationToken = default) => + _userRepository.UpdateAsync(entity, cancellationToken); + + public Task DeleteAsync(DbUser entity, CancellationToken cancellationToken = default) => + _userRepository.DeleteAsync(entity, cancellationToken); + + public Task SoftDeleteAsync(DbUser entity, CancellationToken cancellationToken = default) => + _userRepository.SoftDeleteAsync(entity, cancellationToken); + + public Task SaveChangesAsync(CancellationToken cancellationToken = default) => + _userRepository.SaveChangesAsync(cancellationToken); + + // IUserRepository specific methods public async Task FindByUsernameAsync(string username, CancellationToken cancellationToken = default) => - await DbSet.FirstOrDefaultAsync(u => u.Username == username, cancellationToken); + await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == username, cancellationToken); public async Task UserExistsAsync(string username, CancellationToken cancellationToken = default) => - await DbSet.AnyAsync(u => u.Username == username, cancellationToken); + await _dbContext.Users.AnyAsync(u => u.Username == username, cancellationToken); public async Task GetRefreshTokenCountAsync(int userId, CancellationToken cancellationToken = default) => - await DbContext.RefreshTokens.CountAsync(t => t.DbUser.Id == userId, cancellationToken); + await _dbContext.RefreshTokens.CountAsync(t => t.DbUser.Id == userId, cancellationToken); public async Task GetOldestRefreshTokenAsync(int userId, CancellationToken cancellationToken = default) => - await DbContext.RefreshTokens + await _dbContext.RefreshTokens .Where(t => t.DbUser.Id == userId) .OrderBy(t => t.Expires) .FirstOrDefaultAsync(cancellationToken); public async Task AddRefreshTokenAsync(DbRefreshToken token, CancellationToken cancellationToken = default) => - await DbContext.RefreshTokens.AddAsync(token, cancellationToken); + await _dbContext.RefreshTokens.AddAsync(token, cancellationToken); public async Task RemoveRefreshTokenAsync(string tokenString, CancellationToken cancellationToken = default) { - var token = await DbContext.RefreshTokens.FirstOrDefaultAsync(t => t.Token == tokenString, cancellationToken); + var token = await _dbContext.RefreshTokens.FirstOrDefaultAsync(t => t.Token == tokenString, cancellationToken); if (token != null) - DbContext.RefreshTokens.Remove(token); + _dbContext.RefreshTokens.Remove(token); } public async Task FindRefreshTokenAsync(string tokenString, CancellationToken cancellationToken = default) => - await DbContext.RefreshTokens + await _dbContext.RefreshTokens .Include(t => t.DbUser) .FirstOrDefaultAsync(t => t.Token == tokenString, cancellationToken); }