public async Task <DistanceCombinationCompetitor> AddNewCompetitorAsync(Guid competitorId, Guid distanceCombinationId, int?reserve,
                                                                                DistanceCombinationCompetitorStatus status)
        {
            using (var transaction = context.UseOrBeginTransaction(IsolationLevel.RepeatableRead))
                try
                {
                    var competitor = await context.Competitors.FirstOrDefaultAsync(c => c.Id == competitorId);

                    if (competitor == null)
                    {
                        throw new CompetitorNotFoundException();
                    }

                    var combination = await context.DistanceCombinations.FirstOrDefaultAsync(c => c.Id == distanceCombinationId);

                    if (combination == null)
                    {
                        throw new DistanceCombinationNotFoundException();
                    }

                    CategoryFilter.EnsureMatch(combination.CategoryFilter, competitor.Category);
                    ClassFilter.EnsureMatch(combination.ClassFilter, competitor.Class);

                    var combinationCompetitor = new DistanceCombinationCompetitor
                    {
                        DistanceCombination = combination,
                        Competitor          = competitor,
                        Reserve             = reserve,
                        Status = status
                    };

                    context.DistanceCombinationCompetitors.Add(combinationCompetitor);
                    await context.SaveChangesAsync();

                    recorder.RecordEvent(new DistanceCombinationClassificationChangedEvent(combination));

                    transaction.Commit();
                    return(combinationCompetitor);
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
        }
        public async Task UpdateCompetitorAsync(Guid competitionId, Guid competitorId, IReadOnlyCollection <DistanceCombinationCompetitor> competitorCombinations)
        {
            using (var transaction = context.BeginTransaction(IsolationLevel.RepeatableRead))
                try
                {
                    var competitor = await context.Competitors.FirstOrDefaultAsync(c => c.Id == competitorId);

                    if (competitor == null)
                    {
                        throw new CompetitorNotFoundException();
                    }

                    foreach (var combination in await Combinations(competitionId, competitorId).ToListAsync())
                    {
                        context.DistanceCombinationCompetitors.Remove(combination);
                    }

                    var combinations = (from c in competitorCombinations
                                        join dc in await Combinations(competitionId).ToListAsync() on c.DistanceCombinationId equals dc.Id
                                        select new
                    {
                        Competitor = c,
                        Combination = dc
                    }).ToList();

                    foreach (var c in combinations)
                    {
                        CategoryFilter.EnsureMatch(c.Combination.CategoryFilter, competitor.Category);
                        ClassFilter.EnsureMatch(c.Combination.ClassFilter, competitor.Class);

                        c.Competitor.Competitor = competitor;
                        context.DistanceCombinationCompetitors.Add(c.Competitor);

                        if (c.Competitor.Status == DistanceCombinationCompetitorStatus.Withdrawn)
                        {
                            var competitorRaces = await(from r in context.Races
                                                        where r.Distance.Combinations.Any(dc => dc.Id == c.Combination.Id) && r.CompetitorId == c.Competitor.CompetitorId
                                                        select r).ToListAsync();
                            foreach (var race in competitorRaces)
                            {
                                context.Races.Remove(race);
                            }
                        }
                    }

                    if (competitorCombinations.Any(cc => cc.Status == DistanceCombinationCompetitorStatus.Confirmed || cc.Status == DistanceCombinationCompetitorStatus.Withdrawn))
                    {
                        competitor.Status = CompetitorStatus.Confirmed;
                    }
                    else if (competitorCombinations.All(cc => cc.Status == DistanceCombinationCompetitorStatus.Pending))
                    {
                        competitor.Status = CompetitorStatus.Pending;
                    }

                    await context.SaveChangesAsync();

                    foreach (var combination in combinations.Select(c => c.Combination))
                    {
                        recorder.RecordEvent(new DistanceCombinationClassificationChangedEvent(combination));
                    }

                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
        }