i have problem according an api that is the supposed to get analytics of most won challenges in gamification system , it's supposed to get the top 3 won challenges data based on how many distinct users got milestone on that challenge , this is my query that cause the error
var topChallenges = await ChallengeRepository.GetAllAsQueryable()
.Where(c =>
c.ChallengeStatus != ChallengeStatusEnum.Draft &&
(!request.Data.MainDate.From.HasValue || c.StartDate >= request.Data.MainDate.From) &&
(!request.Data.MainDate.To.HasValue || c.EndDate <= request.Data.MainDate.To) &&
(!request.Data.IsDeleted.HasValue || c.IsDeleted == request.Data.IsDeleted) &&
(request.Data.ChallengeStatus == null || request.Data.ChallengeStatus.Contains(c.ChallengeStatus)) &&
(request.Data.Segments == null || request.Data.Segments.Count == 0 ||
c.ChallengeFilters.Any(s => request.Data.Segments.Select(x => x.Value).Contains(s.Value)))
)
.OrderByDescending(c => c.Milestones.Select(m => m.UserId).Distinct().Count())
.Take(3)
.Select(c => new
{
c,
DistinctUserCount = c.Milestones.Select(m => m.UserId).Distinct().Count(),
Name = c.ChallengeResources
.Where(r => r.SupportedLanguageId == Language.Id)
.Select(r => r.Name)
.FirstOrDefault(),
ImagePath = c.ChallengeImages
.OrderBy(ci => ci.Id)
.Select(ci => ci.Image)
.FirstOrDefault()
})
.AsNoTracking()
.ToListAsync();
then i tried to enhance it by not doing the same distinct user count calculation twice at the same time
and i tried this approach
var filteredChallenges = await ChallengeRepository.GetAllAsQueryable()
.Where(c =>
c.ChallengeStatus != ChallengeStatusEnum.Draft &&
(!request.Data.MainDate.From.HasValue || c.StartDate >= request.Data.MainDate.From) &&
(!request.Data.MainDate.To.HasValue || c.EndDate <= request.Data.MainDate.To) &&
(!request.Data.IsDeleted.HasValue || c.IsDeleted == request.Data.IsDeleted) &&
(request.Data.ChallengeStatus == null || request.Data.ChallengeStatus.Contains(c.ChallengeStatus)) &&
(request.Data.Segments == null || request.Data.Segments.Count == 0 ||
c.ChallengeFilters.Any(s => request.Data.Segments.Select(x => x.Value).Contains(s.Value)))
)
.Select(c => new
{
c.Id,
c.ChallengeStatus,
c.StartDate,
c.EndDate,
DistinctUserCount = c.Milestones.Select(m => m.UserId).Distinct().Count(),
Name = c.ChallengeResources
.Where(r => r.SupportedLanguageId == Language.Id)
.Select(r => r.Name)
.FirstOrDefault(),
ImagePath = c.ChallengeImages
.OrderBy(ci => ci.Id)
.Select(ci => ci.Image)
.FirstOrDefault()
})
.AsNoTracking()
.ToListAsync();
var topChallenges = filteredChallenges
.OrderByDescending(c => c.DistinctUserCount)
.Take(3)
.ToList();
then i tried another approach to remove .Include(c => c.milestones)
and to completely sperate calculations into different steps using this approach
var challengeIdsWithCounts = await ChallengeRepository.GetAllAsQueryable()
.Where(c =>
c.ChallengeStatus != ChallengeStatusEnum.Draft &&
(!request.Data.MainDate.From.HasValue || c.StartDate >= request.Data.MainDate.From) &&
(!request.Data.MainDate.To.HasValue || c.EndDate <= request.Data.MainDate.To) &&
(!request.Data.IsDeleted.HasValue || c.IsDeleted == request.Data.IsDeleted) &&
(request.Data.ChallengeStatus == null || request.Data.ChallengeStatus.Contains(c.ChallengeStatus)) &&
(request.Data.Segments == null || request.Data.Segments.Count == 0 ||
c.ChallengeFilters.Any(s => request.Data.Segments.Select(x => x.Value).Contains(s.Value)))
)
.Select(c => new
{
ChallengeId = c.Id,
DistinctUserCount = c.Milestones.Select(m => m.UserId).Distinct().Count() // Database does the counting
})
.AsNoTracking()
.ToListAsync();
var topChallengeIds = challengeIdsWithCounts
.OrderByDescending(c => c.DistinctUserCount)
.Take(3)
.Select(c => c.ChallengeId)
.ToList();
var topChallenges = await ChallengeRepository.GetAllAsQueryable()
.Where(c => topChallengeIds.Contains(c.Id))
.Select(c => new
{
c.Id,
c.ChallengeStatus,
c.StartDate,
c.EndDate,
DistinctUserCount = c.Milestones.Select(m => m.UserId).Distinct().Count(),
Name = c.ChallengeResources
.Where(r => r.SupportedLanguageId == Language.Id)
.Select(r => r.Name)
.FirstOrDefault(),
ImagePath = c.ChallengeImages
.OrderBy(ci => ci.Id)
.Select(ci => ci.Image)
.FirstOrDefault()
})
.AsNoTracking()
.ToListAsync();
topChallenges = topChallenges
.OrderByDescending(c => c.DistinctUserCount)
.ToList();
and in all 3 approaches i keep getting this error
Something went wrong A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913. SourceContext: (Dsquares.Logging.Middleware.Request_Respons_Middleware)
i even checked the link on how to avoid threading issues on microsoft , but i still can't figure out what is the problem ? also my db context is registered as scoped not singleton