using System.Text.Json; using Managing.Application.Abstractions.Repositories; using Managing.Domain.Backtests; using Managing.Domain.Users; using Microsoft.EntityFrameworkCore; namespace Managing.Infrastructure.Databases.PostgreSql; public class PostgreSqlGeneticRepository : IGeneticRepository { private readonly ManagingDbContext _context; public PostgreSqlGeneticRepository(ManagingDbContext context) { _context = context; } public void InsertGeneticRequestForUser(User user, GeneticRequest geneticRequest) { geneticRequest.User = user; var geneticRequestEntity = PostgreSqlMappers.Map(geneticRequest); // Handle User relationship - check if user exists or create new one if (user != null) { var existingUser = _context.Users .AsTracking() // Explicitly enable tracking for this operation .FirstOrDefault(u => u.Name == user.Name); if (existingUser != null) { geneticRequestEntity.UserId = existingUser.Id; geneticRequestEntity.User = null; // Prevent EF from trying to insert duplicate user } else { // Let EF handle the new user creation geneticRequestEntity.UserId = null; } } _context.GeneticRequests.Add(geneticRequestEntity); _context.SaveChanges(); } public IEnumerable GetGeneticRequestsByUser(User user) { // Use synchronous operations and AsNoTracking to avoid concurrency issues var geneticRequestEntities = _context.GeneticRequests .AsNoTracking() .Include(gr => gr.User) .Where(gr => gr.User != null && gr.User.Name == user.Name) .OrderByDescending(gr => gr.CreatedAt) .ToList(); return PostgreSqlMappers.Map(geneticRequestEntities); } public GeneticRequest GetGeneticRequestByIdForUser(User user, string id) { // Use synchronous operations and AsNoTracking to avoid concurrency issues var geneticRequestEntity = _context.GeneticRequests .AsNoTracking() .Include(gr => gr.User) .FirstOrDefault(gr => gr.RequestId == id); // Check if genetic request exists and belongs to the user if (geneticRequestEntity != null && geneticRequestEntity.User != null && geneticRequestEntity.User.Name == user.Name) { return PostgreSqlMappers.Map(geneticRequestEntity); } return null; } public async Task UpdateGeneticRequestAsync(GeneticRequest geneticRequest) { var existingEntity = await _context.GeneticRequests .AsTracking() // Explicitly enable tracking to ensure entity is tracked .Include(gr => gr.User) .FirstOrDefaultAsync(gr => gr.RequestId == geneticRequest.RequestId); if (existingEntity != null) { // Update the existing entity with new values existingEntity.CompletedAt = geneticRequest.CompletedAt; existingEntity.UpdatedAt = DateTime.UtcNow; existingEntity.Status = geneticRequest.Status.ToString(); existingEntity.BestFitness = geneticRequest.BestFitness; existingEntity.BestIndividual = geneticRequest.BestIndividual; existingEntity.ErrorMessage = geneticRequest.ErrorMessage; existingEntity.ProgressInfo = geneticRequest.ProgressInfo; existingEntity.BestChromosome = geneticRequest.BestChromosome; existingEntity.BestFitnessSoFar = geneticRequest.BestFitnessSoFar; existingEntity.CurrentGeneration = geneticRequest.CurrentGeneration; // Update EligibleIndicators JSON if (geneticRequest.EligibleIndicators != null && geneticRequest.EligibleIndicators.Any()) { try { existingEntity.EligibleIndicatorsJson = JsonSerializer.Serialize(geneticRequest.EligibleIndicators); } catch { existingEntity.EligibleIndicatorsJson = "[]"; } } else { existingEntity.EligibleIndicatorsJson = "[]"; } // Save changes - entity is tracked so changes will be persisted await _context.SaveChangesAsync(); } else { throw new InvalidOperationException($"Genetic request with RequestId '{geneticRequest.RequestId}' not found in database"); } } public void DeleteGeneticRequestByIdForUser(User user, string id) { var geneticRequestEntity = _context.GeneticRequests .Include(gr => gr.User) .FirstOrDefault(gr => gr.RequestId == id); if (geneticRequestEntity != null && geneticRequestEntity.User != null && geneticRequestEntity.User.Name == user.Name) { _context.GeneticRequests.Remove(geneticRequestEntity); _context.SaveChanges(); } } public void DeleteAllGeneticRequestsForUser(User user) { var geneticRequestEntities = _context.GeneticRequests .Include(gr => gr.User) .Where(gr => gr.User != null && gr.User.Name == user.Name) .ToList(); if (geneticRequestEntities.Any()) { _context.GeneticRequests.RemoveRange(geneticRequestEntities); _context.SaveChanges(); } } public async Task> GetGeneticRequestsAsync(GeneticRequestStatus status) { var requests = await _context.GeneticRequests .AsNoTracking() .Include(gr => gr.User) .Where(gr => gr.Status == status.ToString()) .OrderBy(gr => gr.CreatedAt) .ToListAsync(); return PostgreSqlMappers.Map(requests).ToList(); } }