public static IChallenge ToEntity(this ChallengeModel model) { var challenge = new Challenge( ChallengeId.FromGuid(model.Id), new ChallengeName(model.Name), Game.FromValue(model.Game), new BestOf(model.BestOf), new Entries(model.Entries), new ChallengeTimeline(new DateTimeProvider(model.Timeline.CreatedAt), new ChallengeDuration(TimeSpan.FromTicks(model.Timeline.Duration))), model.ScoringItems.ToEntity()); foreach (var participant in model.Participants.Select(participant => participant.ToEntity())) { challenge.Register(participant); } if (model.Timeline.StartedAt.HasValue) { challenge.Start(new DateTimeProvider(model.Timeline.StartedAt.Value)); } if (model.SynchronizedAt.HasValue) { challenge.Synchronize(new DateTimeProvider(model.SynchronizedAt.Value)); } if (model.Timeline.ClosedAt.HasValue) { challenge.Close(new DateTimeProvider(model.Timeline.ClosedAt.Value)); } challenge.ClearDomainEvents(); return(challenge); }
public async Task When(CreateWorkout cmd) { var workoutId = new WorkoutId(cmd.Id); var challengeId = new ChallengeId(cmd.ChallengeId); await Update(workoutId, w => w.Create(workoutId, challengeId, new CoreDomain.Types.WorkoutType(cmd.WorkoutType), cmd.Repetitions)); }
public async Task ShouldBeHttpStatusCodeOK() { // Arrange var challengeFaker = TestData.FakerFactory.CreateChallengeFaker(1, Game.LeagueOfLegends, ChallengeState.Inscription); var challenge = challengeFaker.FakeChallenge(); var factory = TestHost.WithClaimsFromDefaultAuthentication(); _httpClient = factory.CreateClient(); var testServer = factory.Server; testServer.CleanupDbContext(); await testServer.UsingScopeAsync( async scope => { var challengeRepository = scope.GetRequiredService <IChallengeRepository>(); challengeRepository.Create(challenge); await challengeRepository.CommitAsync(false); }); // Act using var response = await this.ExecuteAsync(ChallengeId.FromGuid(challenge.Id)); // Assert response.EnsureSuccessStatusCode(); response.StatusCode.Should().Be(HttpStatusCode.OK); var participantResponses = await response.Content.ReadAsJsonAsync <ChallengeParticipantDto[]>(); participantResponses.Should().HaveCount(challenge.Participants.Count); }
public WorkoutCreated(WorkoutId id, ChallengeId challengeId, WorkoutType type, int reps, DateTime eventDateTime) : base(eventDateTime) { Id = id; ChallengeId = challengeId; Type = type; Reps = reps; }
public async Task SynchronizeChallenge_ShouldBeOfTypeSynchronizeChallengeResponse() { // Arrange var userId = new UserId(); const string email = "*****@*****.**"; var challengeId = new ChallengeId(); var claims = new[] { new Claim(JwtClaimTypes.Subject, userId.ToString()), new Claim(JwtClaimTypes.Email, email) }; var host = TestHost.WithClaimsFromBearerAuthentication(claims); host.Server.CleanupDbContext(); await host.Server.UsingScopeAsync( async scope => { var challengeRepository = scope.GetRequiredService <IChallengeRepository>(); var challenge = new Challenge( challengeId, new ChallengeName("test"), Game.LeagueOfLegends, BestOf.Five, Entries.Two, new ChallengeTimeline(new UtcNowDateTimeProvider(), ChallengeDuration.FiveDays), new Scoring()); challenge.Register( new Participant( new ParticipantId(), new UserId(), new PlayerId(), new UtcNowDateTimeProvider())); challenge.Register( new Participant( new ParticipantId(), new UserId(), new PlayerId(), new UtcNowDateTimeProvider())); challenge.Start(new UtcNowDateTimeProvider()); challengeRepository.Create(challenge); await challengeRepository.CommitAsync(false); }); var request = new SynchronizeChallengeRequest { ChallengeId = challengeId }; var client = new ChallengeService.ChallengeServiceClient(host.CreateChannel()); // Act var response = await client.SynchronizeChallengeAsync(request); //Assert response.Should().BeOfType <SynchronizeChallengeResponse>(); }
public void Create(ChallengeId id, int repetitions, string description) { if (State.Created) { throw new InvalidOperationException($"{nameof(Challenge)} already created"); } Apply(new ChallengeCreated(id, repetitions, description, DateTime.Now)); }
public void Create(WorkoutId id, ChallengeId challengeId, WorkoutType type, int repetitions) { if (State.Created) { throw new InvalidOperationException($"{nameof(Workout)}-{id} already created"); } Apply(new WorkoutCreated(id, challengeId, type, repetitions, DateTime.Now)); }
public async Task RegisterChallengeParticipant_ShouldThrowFailedPreconditionRpcException() { // Arrange var userId = new UserId(); const string email = "*****@*****.**"; var challengeId = new ChallengeId(); var claims = new[] { new Claim(JwtClaimTypes.Subject, userId.ToString()), new Claim(JwtClaimTypes.Email, email) }; var host = TestHost.WithClaimsFromBearerAuthentication(claims); host.Server.CleanupDbContext(); await host.Server.UsingScopeAsync( async scope => { var challengeRepository = scope.GetRequiredService <IChallengeRepository>(); var challenge = new Challenge( challengeId, new ChallengeName("test"), Game.LeagueOfLegends, BestOf.Five, Entries.Two, new ChallengeTimeline(new UtcNowDateTimeProvider(), ChallengeDuration.FiveDays), new Scoring()); challenge.Register( new Participant( new ParticipantId(), new UserId(), new PlayerId(), new UtcNowDateTimeProvider())); challenge.Register( new Participant( new ParticipantId(), new UserId(), new PlayerId(), new UtcNowDateTimeProvider())); challengeRepository.Create(challenge); await challengeRepository.CommitAsync(false); }); var request = new RegisterChallengeParticipantRequest { ChallengeId = challengeId, GamePlayerId = new PlayerId(), ParticipantId = new ParticipantId() }; var client = new ChallengeService.ChallengeServiceClient(host.CreateChannel()); // Act Assert var func = new Func <Task>(async() => await client.RegisterChallengeParticipantAsync(request)); func.Should().Throw <RpcException>(); }
protected override async Task SeedProductionAsync() { var scoring = new Scoring( new Dictionary <string, float> { ["Kills"] = 4.5F, ["Deaths"] = -4F, ["Assists"] = 3.5F, ["TotalDamageDealtToChampions"] = 0.0009F, ["TotalDamageTaken"] = 0.00125F, ["TotalMinionsKilled"] = 0.04F, ["VisionScore"] = 0.38F, ["Winner"] = 20F }); var assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) !; var file = File.OpenRead(Path.Combine(assemblyPath, "Setup/Challenges.Production.csv")); using var csvReader = file.OpenCsvReader(); var challenges = csvReader.GetRecords( new { Id = default(Guid), Name = default(string), Game = default(int), Entries = default(int), BestOf = default(int), Duration = default(long), State = default(int) }) .Select( record => { var timeline = new ChallengeTimeline( new UtcNowDateTimeProvider(), new ChallengeDuration(TimeSpan.FromSeconds(record.Duration))); return(new Challenge( ChallengeId.FromGuid(record.Id), new ChallengeName(record.Name !), Game.FromValue(record.Game), new BestOf(record.BestOf), new Entries(record.Entries), timeline, scoring)); }); Challenges.AddRange( challenges.Where(challenge => Challenges.All(x => x.Id != challenge.Id)) .Select(challenge => challenge.ToModel())); await this.CommitAsync(); }
public async Task <IActionResult> FetchChallengeParticipantsAsync(ChallengeId challengeId) { var participants = await _participantQuery.FetchChallengeParticipantsAsync(challengeId); if (!participants.Any()) { return(this.NoContent()); } return(this.Ok(_mapper.Map <IReadOnlyCollection <ChallengeParticipantDto> >(participants))); }
public static IChallenge ToEntity(this ChallengeModel model) { var entryFee = new EntryFee(model.EntryFeeAmount, CurrencyType.FromValue(model.EntryFeeCurrency)); var payout = new ChallengePayout(entryFee, new ChallengePayoutBuckets(model.PayoutBuckets.Select(bucket => bucket.ToEntity()))); var challenge = new Challenge(ChallengeId.FromGuid(model.Id), payout); challenge.ClearDomainEvents(); return(challenge); }
public async Task HandleAsync_ChallengeSynchronizedIntegrationEventIsValid_ShouldBeCompletedTask() { // Arrange var challengeId = new ChallengeId(); var factory = new ChallengePayoutFactory(); var strategy = factory.CreateInstance(); var payout = strategy.GetChallengePayout(ChallengePayoutEntries.Five, MoneyEntryFee.Fifty); var challenge = new Challenge(challengeId, payout); var mockLogger = new MockLogger <ChallengeSynchronizedIntegrationEventHandler>(); TestMock.ChallengeService.Setup(challengeService => challengeService.ChallengeExistsAsync(It.IsAny <ChallengeId>())).ReturnsAsync(true).Verifiable(); TestMock.ChallengeService.Setup(challengeService => challengeService.FindChallengeAsync(It.IsAny <ChallengeId>())) .ReturnsAsync(challenge) .Verifiable(); TestMock.ChallengeService .Setup( challengeService => challengeService.CloseChallengeAsync( It.IsAny <IChallenge>(), It.IsAny <Dictionary <UserId, decimal?> >(), It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask) .Verifiable(); var handler = new ChallengeSynchronizedIntegrationEventHandler(TestMock.ChallengeService.Object, mockLogger.Object); var integrationEvent = new ChallengeSynchronizedIntegrationEvent { ChallengeId = new ChallengeId() }; // Act await handler.HandleAsync(integrationEvent); // Assert TestMock.ChallengeService.Verify(challengeService => challengeService.ChallengeExistsAsync(It.IsAny <ChallengeId>()), Times.Once); TestMock.ChallengeService.Verify(challengeService => challengeService.FindChallengeAsync(It.IsAny <ChallengeId>()), Times.Once); TestMock.ChallengeService.Verify( challengeService => challengeService.CloseChallengeAsync( It.IsAny <IChallenge>(), It.IsAny <Dictionary <UserId, decimal?> >(), It.IsAny <CancellationToken>()), Times.Once); mockLogger.Verify(Times.Once()); }
public static async Task PublishChallengeParticipantRegisteredIntegrationEventAsync( this IServiceBusPublisher publisher, ChallengeId challengeId, UserId userId, ParticipantId participantId ) { var integrationEvent = new ChallengeParticipantRegisteredIntegrationEvent { Participant = new ChallengeParticipantDto { Id = participantId, ChallengeId = challengeId, UserId = userId } }; await publisher.PublishAsync(integrationEvent); }
public void GetHashCode_ShouldNotBeZero() { // Arrange var challengeId = new ChallengeId(); var factory = new ChallengePayoutFactory(); var instance = factory.CreateInstance(); var scoreboard = new Dictionary <UserId, decimal?> { { new UserId(), 50 }, { new UserId(), 100 } }; var challenge = new Challenge( challengeId, instance.GetChallengePayout(new ChallengePayoutEntries(scoreboard.Count / 2), new EntryFee(100, CurrencyType.Money))); // Act Assert challenge.GetHashCode().Should().NotBe(0); }
private async Task SeedChallengesAsync() { var strategy = _challengePayoutFactory.CreateInstance(); var twoDollars = new EntryFee(2, CurrencyType.Money); var threeDollars = new EntryFee(3, CurrencyType.Money); var twoDollarsForOneEntries = strategy.GetChallengePayout(ChallengePayoutEntries.One, twoDollars); var twoDollarsForTwoEntries = strategy.GetChallengePayout(ChallengePayoutEntries.Two, twoDollars); var twoDollarsForThreeEntries = strategy.GetChallengePayout(ChallengePayoutEntries.Three, twoDollars); var threeDollarsForOneEntries = strategy.GetChallengePayout(ChallengePayoutEntries.One, threeDollars); var threeDollarsForTwoEntries = strategy.GetChallengePayout(ChallengePayoutEntries.Two, threeDollars); var threeDollarsForThreeEntries = strategy.GetChallengePayout(ChallengePayoutEntries.Three, threeDollars); var challenges = new List <IChallenge> { new Challenge(ChallengeId.Parse("d53b366f-e717-43d4-ac12-6e13d37f5cef"), twoDollarsForOneEntries), new Challenge(ChallengeId.Parse("369ae69d-b10d-4d72-84ba-698691646ba6"), twoDollarsForOneEntries), new Challenge(ChallengeId.Parse("eb76fa60-700f-4dce-b312-d69897563437"), twoDollarsForTwoEntries), new Challenge(ChallengeId.Parse("82592581-e6ac-41e0-9c61-773d924f233d"), twoDollarsForTwoEntries), new Challenge(ChallengeId.Parse("9457ae9a-4e5c-436f-b10f-33134af68439"), twoDollarsForThreeEntries), new Challenge(ChallengeId.Parse("91f6d007-b458-4f1c-9814-755b32059e00"), twoDollarsForThreeEntries), new Challenge(ChallengeId.Parse("4ecb13a4-0742-4140-93b0-27ee582e5cab"), threeDollarsForOneEntries), new Challenge(ChallengeId.Parse("fa38f697-2ef3-40e9-a165-d62c3cc750a8"), threeDollarsForOneEntries), new Challenge(ChallengeId.Parse("ac6851b4-2cb7-42ab-bf44-fb197d21221b"), threeDollarsForTwoEntries), new Challenge(ChallengeId.Parse("bb5f6e0c-ada7-47b4-9d24-a3c9ec7df034"), threeDollarsForTwoEntries), new Challenge(ChallengeId.Parse("6ec217f7-3d6a-41c2-b2eb-4cc8799d2af5"), threeDollarsForThreeEntries), new Challenge(ChallengeId.Parse("7d96b314-8d5b-4393-9257-9c0e2cf7c0f1"), threeDollarsForThreeEntries) }; Challenges.AddRange(challenges.Where(challenge => Challenges.All(x => x.Id != challenge.Id)).Select(challenge => challenge.ToModel())); await this.CommitAsync(); }
public static async Task PublishChallengeClosedIntegrationEventAsync( this IServiceBusPublisher publisher, ChallengeId challengeId, ChallengeParticipantPayouts payouts ) { var integrationEvent = new ChallengeClosedIntegrationEvent { ChallengeId = challengeId, PayoutPrizes = { payouts.ToDictionary( payoutPrize => payoutPrize.Key.ToString(), payoutPrize => new CurrencyDto { Amount = payoutPrize.Value.Amount, Type = payoutPrize.Value.Type.ToEnum <EnumCurrencyType>() }) } }; await publisher.PublishAsync(integrationEvent); }
public async Task FindChallengePayout_ShouldBeOfTypeFindChallengePayoutResponse() { // Arrange var userId = new UserId(); const string email = "*****@*****.**"; var challengeId = new ChallengeId(); var claims = new[] { new Claim(JwtClaimTypes.Subject, userId.ToString()), new Claim(JwtClaimTypes.Email, email) }; var host = TestHost.WithClaimsFromBearerAuthentication(claims); host.Server.CleanupDbContext(); await host.Server.UsingScopeAsync( async scope => { var accountService = scope.GetRequiredService <IAccountService>(); var challengeService = scope.GetRequiredService <IChallengeService>(); await accountService.CreateAccountAsync(userId); await challengeService.CreateChallengeAsync(challengeId, ChallengePayoutEntries.Fifteen, new EntryFee(20, CurrencyType.Money)); }); var request = new FindChallengePayoutRequest { ChallengeId = challengeId }; var client = new CashierService.CashierServiceClient(host.CreateChannel()); // Act var response = await client.FindChallengePayoutAsync(request); //Assert response.Should().BeOfType <FindChallengePayoutResponse>(); }
public async Task <DomainValidationResult <IChallenge> > CreateChallengeAsync( ChallengeId challengeId, ChallengePayoutEntries payoutEntries, EntryFee entryFee, CancellationToken cancellationToken = default ) { var result = new DomainValidationResult <IChallenge>(); var strategy = _challengePayoutFactory.CreateInstance(); if (payoutEntries == 0) { return(result.AddFailedPreconditionError("Challenge payout entries cannot be zero.")); } var payout = strategy.GetChallengePayout(payoutEntries, entryFee); if (payout == null) { return(result.AddFailedPreconditionError("Invalid payout structure. Payout entries doesn't match the chart.")); } if (result.IsValid) { var challenge = new Challenge(challengeId, payout !); _challengeRepository.Create(challenge); await _challengeRepository.CommitAsync(true, cancellationToken); return(challenge); } return(result); }
public void Equals_WithSameId_ShouldBeTrue() { // Arrange var challengeId = new ChallengeId(); var factory = new ChallengePayoutFactory(); var instance = factory.CreateInstance(); var scoreboard = new Dictionary <UserId, decimal?> { { new UserId(), 50 }, { new UserId(), 100 } }; var challenge1 = new Challenge( challengeId, instance.GetChallengePayout(new ChallengePayoutEntries(scoreboard.Count / 2), new EntryFee(100, CurrencyType.Money))); var challenge2 = new Challenge( challengeId, instance.GetChallengePayout(new ChallengePayoutEntries(scoreboard.Count / 2), new EntryFee(100, CurrencyType.Money))); // Act Assert challenge1.Equals(challenge2).Should().BeTrue(); }
public ChallengeId Id() { return(ChallengeId.FromGuid(Faker.Random.Guid())); }
public async Task <bool> ChallengeExistsAsync(ChallengeId challengeId) { return(await _challengeRepository.ChallengeExistsAsync(challengeId)); }
public async Task <IChallenge> FindChallengeAsync(ChallengeId challengeId) { return(await _challengeRepository.FindChallengeAsync(challengeId)); }
public async Task HandleAsync_WhenChallengeClosedIntegrationEventIsValid_ShouldBeCompletedTask() { // Arrange var challengeId = new ChallengeId(); var scoring = new Scoring { { new StatName(Game.LeagueOfLegends), new StatWeighting(50.0f) } }; var challenge = new Challenge( challengeId, new ChallengeName("test"), Game.LeagueOfLegends, BestOf.Five, Entries.Four, new ChallengeTimeline(new DateTimeProvider(DateTime.Now.AddDays(-1)), ChallengeDuration.OneDay), scoring); var mockLogger = new MockLogger <ChallengeClosedIntegrationEventHandler>(); TestMock.ChallengeService.Setup(challengeService => challengeService.ChallengeExistsAsync(It.IsAny <ChallengeId>())).ReturnsAsync(true).Verifiable(); TestMock.ChallengeService.Setup(challengeService => challengeService.FindChallengeAsync(It.IsAny <ChallengeId>())) .ReturnsAsync(challenge) .Verifiable(); TestMock.ChallengeService .Setup( challengeService => challengeService.CloseChallengeAsync( It.IsAny <Challenge>(), It.IsAny <IDateTimeProvider>(), It.IsAny <CancellationToken>())) .ReturnsAsync(new DomainValidationResult <IChallenge>()) .Verifiable(); var handler = new ChallengeClosedIntegrationEventHandler(TestMock.ChallengeService.Object, mockLogger.Object); var integrationEvent = new ChallengeClosedIntegrationEvent { ChallengeId = new ChallengeId(), PayoutPrizes = { { "test1", new CurrencyDto { Amount = 50.0m, Type = EnumCurrencyType.Money } } } }; // Act await handler.HandleAsync(integrationEvent); // Assert TestMock.ChallengeService.Verify(challengeService => challengeService.ChallengeExistsAsync(It.IsAny <ChallengeId>()), Times.Once); TestMock.ChallengeService.Verify(challengeService => challengeService.FindChallengeAsync(It.IsAny <ChallengeId>()), Times.Once); TestMock.ChallengeService.Verify( challengeService => challengeService.CloseChallengeAsync(It.IsAny <Challenge>(), It.IsAny <IDateTimeProvider>(), It.IsAny <CancellationToken>()), Times.Once); mockLogger.Verify(Times.Once()); }
public ChallengeParticipantRegisteredDomainEvent(ChallengeId challengeId, ParticipantId participantId, UserId userId) { ChallengeId = challengeId; ParticipantId = participantId; UserId = userId; }
public ChallengeDurationChanged(ChallengeId id, TimeSpan duration, DateTime eventDateTime) : base(eventDateTime) { Id = id; Duration = duration; }
public WorkoutExecuted(ChallengeId challengeId, int repetitions, DateTime eventDateTime) : base(eventDateTime) { ChallengeId = challengeId; Repetitions = repetitions; }
async Task When(CreateChallenge cmd) { var challengeId = new ChallengeId(cmd.Id); await Update(challengeId, c => c.Create(challengeId, cmd.Repetitions, cmd.Description)); }
private async Task <HttpResponseMessage> ExecuteAsync(ChallengeId challengeId) { return(await _httpClient.GetAsync($"api/challenges/{challengeId}/participants")); }
public ChallengeClosedDomainEvent(ChallengeId challengeId, ChallengeParticipantPayouts payouts) { ChallengeId = challengeId; Payouts = payouts; }
private async Task SeedChallengesAsync() { var scoring = new Scoring( new Dictionary <string, float> { ["Kills"] = 4.5F, ["Deaths"] = -4F, ["Assists"] = 3.5F, ["TotalDamageDealtToChampions"] = 0.0009F, ["TotalDamageTaken"] = 0.00125F, ["TotalMinionsKilled"] = 0.04F, ["VisionScore"] = 0.38F, ["Winner"] = 20F }); var timeline = new ChallengeTimeline(new UtcNowDateTimeProvider(), new ChallengeDuration(TimeSpan.FromDays(1))); var challenges = new List <IChallenge> { new Challenge( ChallengeId.Parse("d53b366f-e717-43d4-ac12-6e13d37f5cef"), new ChallengeName("2$ CHALLENGE BEST OF 1 (2)"), Game.LeagueOfLegends, BestOf.One, Entries.Two, timeline, scoring), new Challenge( ChallengeId.Parse("369ae69d-b10d-4d72-84ba-698691646ba6"), new ChallengeName("3$ CHALLENGE BEST OF 1 (2)"), Game.LeagueOfLegends, BestOf.One, Entries.Two, timeline, scoring), new Challenge( ChallengeId.Parse("eb76fa60-700f-4dce-b312-d69897563437"), new ChallengeName("2$ CHALLENGE BEST OF 1 (4)"), Game.LeagueOfLegends, BestOf.One, Entries.Four, timeline, scoring), new Challenge( ChallengeId.Parse("82592581-e6ac-41e0-9c61-773d924f233d"), new ChallengeName("3$ CHALLENGE BEST OF 1 (4)"), Game.LeagueOfLegends, BestOf.One, Entries.Four, timeline, scoring), new Challenge( ChallengeId.Parse("9457ae9a-4e5c-436f-b10f-33134af68439"), new ChallengeName("2$ CHALLENGE BEST OF 1 (6)"), Game.LeagueOfLegends, BestOf.One, Entries.Six, timeline, scoring), new Challenge( ChallengeId.Parse("91f6d007-b458-4f1c-9814-755b32059e00"), new ChallengeName("3$ CHALLENGE BEST OF 1 (6)"), Game.LeagueOfLegends, BestOf.One, Entries.Six, timeline, scoring), new Challenge( ChallengeId.Parse("4ecb13a4-0742-4140-93b0-27ee582e5cab"), new ChallengeName("2$ CHALLENGE BEST OF 3 (2)"), Game.LeagueOfLegends, BestOf.Three, Entries.Two, timeline, scoring), new Challenge( ChallengeId.Parse("fa38f697-2ef3-40e9-a165-d62c3cc750a8"), new ChallengeName("3$ CHALLENGE BEST OF 3 (2)"), Game.LeagueOfLegends, BestOf.Three, Entries.Two, timeline, scoring), new Challenge( ChallengeId.Parse("ac6851b4-2cb7-42ab-bf44-fb197d21221b"), new ChallengeName("2$ CHALLENGE BEST OF 3 (4)"), Game.LeagueOfLegends, BestOf.Three, Entries.Four, timeline, scoring), new Challenge( ChallengeId.Parse("bb5f6e0c-ada7-47b4-9d24-a3c9ec7df034"), new ChallengeName("3$ CHALLENGE BEST OF 3 (4)"), Game.LeagueOfLegends, BestOf.Three, Entries.Four, timeline, scoring), new Challenge( ChallengeId.Parse("6ec217f7-3d6a-41c2-b2eb-4cc8799d2af5"), new ChallengeName("2$ CHALLENGE BEST OF 3 (6)"), Game.LeagueOfLegends, BestOf.Three, Entries.Six, timeline, scoring), new Challenge( ChallengeId.Parse("7d96b314-8d5b-4393-9257-9c0e2cf7c0f1"), new ChallengeName("3$ CHALLENGE BEST OF 3 (6)"), Game.LeagueOfLegends, BestOf.Three, Entries.Six, timeline, scoring) }; Challenges.AddRange(challenges.Where(challenge => Challenges.All(x => x.Id != challenge.Id)).Select(challenge => challenge.ToModel())); await this.CommitAsync(); }