internal List <DateTime> GetAllAvailableMatchDays(RoundLegEntity roundLeg) { LinqMetaData metaData = new LinqMetaData(_matchPlanner.Adapter); return((from dates in metaData.AvailableMatchDate where dates.TournamentId == _matchPlanner.Tournament.Id && (dates.MatchStartTime >= roundLeg.StartDateTime.Date && dates.MatchStartTime <= roundLeg.EndDateTime.Date.AddDays(1).AddSeconds(-1)) orderby dates.MatchStartTime select dates.MatchStartTime.Date).Distinct().ToList()); }
internal List <DateTime> GetGeneratedAndManualAvailableMatchDateDays(RoundLegEntity leg) { var result = _generatedAvailableMatchDateEntities.Union(_availableMatchDateEntities) .Where(gen => gen.TournamentId == _tenantContext.TournamentContext.MatchPlanTournamentId && gen.MatchStartTime >= leg.StartDateTime.Date && gen.MatchStartTime <= leg.EndDateTime.AddDays(1).AddSeconds(-1)) .OrderBy(gen => gen.MatchStartTime) .Select(gen => gen.MatchStartTime.Date) .Distinct() .ToList(); return(result); }
internal DataTable GetAllAvailableMatchDays_(RoundLegEntity roundLeg) { var fields = new ResultsetFields(1); fields.DefineField(AvailableMatchDateFields.MatchStartTime, 0, "MatchStartTime"); fields[0].ExpressionToApply = new DbFunctionCall("(DATE({0}) + INTERVAL 0 SECOND)", new object[] { AvailableMatchDateFields.MatchStartTime }); IRelationPredicateBucket bucket = new RelationPredicateBucket(AvailableMatchDateFields.TournamentId == _matchPlanner.Tournament.Id); // date within round leg limits IPredicateExpression dateFilter = new PredicateExpression(new FieldBetweenPredicate(fields[0], null, roundLeg.StartDateTime.Date, roundLeg.EndDateTime.Date)); bucket.PredicateExpression.AddWithAnd(dateFilter); ISortExpression sortClause = new SortExpression(new SortClause(fields[0], null, SortOperator.Ascending)); var dynamicList = new DataTable(); _matchPlanner.Adapter.FetchTypedList(fields, dynamicList, bucket, 0, sortClause, true, null); return(dynamicList); }
/// <summary> /// Copies the round basic data and the round leg data /// from the source to an existing target tournament. The new tournament id must /// already exist. Leg data for each round is taken over from target tournament legs /// on a 1:1 base (same number of legs, dates/times). /// </summary> /// <param name="fromTournamentId">Existing source tournament id.</param> /// <param name="toTournamentId">Existing target tournament id.</param> /// <param name="excludeRoundId">List of round id's to be excluded (may be null for none)</param> /// <returns>True, if creation was successful, false otherwise.</returns> public bool CopyRound(long fromTournamentId, long toTournamentId, IEnumerable <long> excludeRoundId) { const string transactionName = "CloneRounds"; if (excludeRoundId == null) { excludeRoundId = new List <long>(); } DateTime now = DateTime.Now; // get the rounds of SOURCE tournament var roundIds = _appDb.TournamentRepository.GetTournamentRounds(fromTournamentId).Select(r => r.Id).ToList(); using var da = _appDb.DbContext.GetNewAdapter(); // da.StartTransaction(System.Data.IsolationLevel.ReadUncommitted, transactionName); var roundsWithLegs = new Queue <RoundEntity>(); foreach (var r in roundIds) { roundsWithLegs.Enqueue(_appDb.RoundRepository.GetRoundWithLegs(r)); } foreach (var r in roundIds) { var round = roundsWithLegs.Dequeue(); // skip excluded round id's if (excludeRoundId.Contains(r)) { continue; } // create new round and overtake data of source round var newRound = new RoundEntity() { TournamentId = toTournamentId, Name = round.Name, Description = round.Description, TypeId = round.TypeId, NumOfLegs = round.NumOfLegs, MatchRuleId = round.MatchRuleId, SetRuleId = round.MatchRuleId, IsComplete = false, CreatedOn = now, ModifiedOn = now, NextRoundId = null }; // create the round leg records based on the TARGET tournament legs foreach (var rl in round.RoundLegs) { var newRoundLeg = new RoundLegEntity() { SequenceNo = rl.SequenceNo, Description = rl.Description, StartDateTime = rl.StartDateTime, EndDateTime = rl.EndDateTime, CreatedOn = now, ModifiedOn = now }; newRound.RoundLegs.Add(newRoundLeg); } // save recursively (new round with its new round legs) if (!da.SaveEntity(newRound, true, true)) { // roll back if any round fails da.Rollback(transactionName); return(false); } } // commit only after all rounds are processed successfully da.Commit(); return(true); }
private bool IsDateWithinRoundLegDateTime(RoundLegEntity leg, DateTime queryDate) { return(queryDate.Date >= leg.StartDateTime.Date && queryDate.Date <= leg.EndDateTime.Date); }
private List <AvailableMatchDateEntity?> GetMatchDates(RoundLegEntity roundLeg, TeamCombinationGroup <long> teamCombinationGroup, EntityCollection <MatchEntity> groupMatches) { // here the resulting match dates are stored: var matchDatePerCombination = new List <AvailableMatchDateEntity?>(); // these are possible date alternatives per combination: var matchDates = new List <List <AvailableMatchDateEntity> >(); for (var index = 0; index < teamCombinationGroup.Count; index++) { var combination = teamCombinationGroup[index]; var availableDates = _availableMatchDates.GetGeneratedAndManualAvailableMatchDates(combination.HomeTeam, teamCombinationGroup.DateTimePeriod, GetOccupiedMatchDates(combination, groupMatches)); // initialize MinTimeDiff for the whole list availableDates.ForEach(amd => amd.MinTimeDiff = TimeSpan.MaxValue); if (availableDates.Count == 0) { availableDates = _availableMatchDates.GetGeneratedAndManualAvailableMatchDates(combination.HomeTeam, new DateTimePeriod(roundLeg.StartDateTime, roundLeg.EndDateTime), GetOccupiedMatchDates(combination, groupMatches)); } matchDates.Add(availableDates); #if DEBUG // Check whether there is a match of this combination var lastMatchOfCombination = groupMatches.OrderBy(gm => gm.PlannedStart).LastOrDefault(gm => gm.HomeTeamId == combination.HomeTeam || gm.GuestTeamId == combination.GuestTeam); if (lastMatchOfCombination != null) { _logger.LogTrace("Last match date found for home team '{0}' and guest team '{1}' is '{2}'", combination.HomeTeam, combination.GuestTeam, lastMatchOfCombination.PlannedStart?.ToShortDateString() ?? "none"); } else { _logger.LogTrace("No last match found for home team '{0}' and guest team '{1}'", combination.HomeTeam, combination.GuestTeam); } #endif } // we can't proceed without and match dates found if (matchDates.Count == 0) { return(matchDatePerCombination); } // only 1 match date found, so optimization is not possible // and the following "i-loop" will be skipped if (matchDates.Count == 1) { matchDatePerCombination.Add(matchDates[0][0]); return(matchDatePerCombination); } // cross-compute the number of dates between between group pairs. // goal: found match dates should be as close together as possible // start with 1st dates, end with last but one dates for (var i = 0; i < matchDates.Count - 1; i++) { // start with 2nd dates, end with last dates for (var j = 1; j < matchDates.Count; j++) { // compare each date in the first list... foreach (var dates1 in matchDates[i]) { // ... with the dates in the second list foreach (var dates2 in matchDates[j]) { var daysDiff = Math.Abs((dates1.MatchStartTime.Date - dates2.MatchStartTime.Date).Days); // save minimum dates found for later reference if (daysDiff < dates1.MinTimeDiff.Days) { dates1.MinTimeDiff = new TimeSpan(daysDiff, 0, 0, 0); } if (daysDiff < dates2.MinTimeDiff.Days) { dates2.MinTimeDiff = new TimeSpan(daysDiff, 0, 0, 0); } } // end dates2 } // end dates1 } // end j // get the date that has least distance to smallest date in other group(s) // Note: If no match dates could be determined for a team, bestDate will be null. var bestDate = matchDates[i].Where(md => md.MinTimeDiff == matchDates[i].Min(d => d.MinTimeDiff)) .OrderBy(md => md.MinTimeDiff).FirstOrDefault(); matchDatePerCombination.Add(bestDate); // process the last combination // in case comparisons took place, // now the "j-loop" group is not processed yet: if (i + 1 >= matchDates.Count - 1) { bestDate = matchDates[^ 1].Where(md => md.MinTimeDiff == matchDates[^ 1].Min(d => d.MinTimeDiff))