示例#1
0
        private List <ApiPlayerBase> GetApiPlayerBases(Feeds.FixtureFeed.ApiFixture feedFixture)
        {
            List <ApiPlayerBase> apiPlayerBases = null;

            // USE LINEUPS AS BASE IF POSSIBLE, INCLUDING MAPPING FROM BOXSCORE BY JERSEY NUMBER AND TEAM
            if (feedFixture.Lineups != null && feedFixture.Lineups.Count > 0)
            {
                if (feedFixture.PlayerBoxscores != null && feedFixture.PlayerBoxscores.Count > 0)
                {
                    // ALL PLAYERS SHOULD BE IN LINEUP. THERE SHOULD BE A MATCH FROM LINEUP TO BOXSCORE. VERIFY MATCHES
                    var apiBoxscorePlayerMapping = from apiLineupPlayer in feedFixture.AllLineupPlayers
                                                   join apiBoxscorePlayer in feedFixture.PlayerBoxscores
                                                   on new { apiLineupPlayer.TeamId, Number = apiLineupPlayer.Number }
                    equals new { apiBoxscorePlayer.TeamId, Number = (int?)apiBoxscorePlayer.Number }
                    into pbx
                    from pbx2 in pbx.DefaultIfEmpty()                                                                                // pbx2 IS PLAYER BOXSCORES BUT WITH NULL VALUES IF NO MATCH (FORCE LEFT JOIN INSTEAD OF INNER JOIN)
                    select new
                    {
                        TeamId           = apiLineupPlayer.TeamId,
                        PlayerName       = apiLineupPlayer.PlayerName,
                        JerseyNumber     = apiLineupPlayer.Number,
                        LineupPlayerId   = apiLineupPlayer.PlayerId,
                        BoxscorePlayerId = pbx2?.PlayerId,
                        IsStarter        = apiLineupPlayer.IsStarter
                    };
                    apiPlayerBases = apiBoxscorePlayerMapping
                                     .Where(x => x.LineupPlayerId.HasValue)
                                     .Select(x => new ApiPlayerBase(x.LineupPlayerId.Value, x.TeamId, x.PlayerName, x.JerseyNumber, x.LineupPlayerId, x.BoxscorePlayerId, x.IsStarter)).ToList();
                }
                else
                {
                    apiPlayerBases = feedFixture.AllLineupPlayers?
                                     .Where(x => x.PlayerId.HasValue)
                                     .Select(x => new ApiPlayerBase(x.PlayerId.Value, x.TeamId, x.PlayerName, x.Number, x.PlayerId.Value, null, x.IsStarter)).ToList();
                }
            }
            else if (feedFixture.PlayerBoxscores != null && feedFixture.PlayerBoxscores.Count > 0)
            {
                apiPlayerBases = feedFixture.PlayerBoxscores.Select(x => new ApiPlayerBase(x.PlayerId.Value, x.TeamId, x.PlayerName, x.Number, null, x.PlayerId, !(x.IsSubstitute ?? true))).ToList();
            }

            if (apiPlayerBases == null || apiPlayerBases.Count == 0)
            {
                return(null);
            }

            if (apiPlayerBases.GroupBy(x => x.PlayerId).Any(y => y.Count() > 1))
            {
                var groupedApiPlayerBases = apiPlayerBases.GroupBy(x => x.PlayerId);
                apiPlayerBases = new List <ApiPlayerBase>();
                foreach (var groupedApiPlayerBase in groupedApiPlayerBases)
                {
                    if (groupedApiPlayerBase.Count() == 1)
                    {
                        apiPlayerBases.Add(groupedApiPlayerBase.First());
                    }
                    else
                    {
                        apiPlayerBases.Add(groupedApiPlayerBase.OrderBy(y => y.BoxscorePlayerId.HasValue ? 0 : 1).ThenBy(y => y.IsStarter ? 0 : 1).First());
                    }
                }
            }

            return(apiPlayerBases);
        }
示例#2
0
        public void Run(SoccerDataContext dbContext)
        {
            var dbFixture      = dbContext.Fixtures.Single(x => x.ApiFootballId == this.ApiFootballFixtureId);
            var isFixtureFinal = string.Equals("Match Finished", dbFixture.Status, StringComparison.CurrentCultureIgnoreCase);

            if (!dbFixture.HomeTeamSeasonId.HasValue ||
                !dbFixture.AwayTeamSeasonId.HasValue ||
                !isFixtureFinal)
            {
                return;
            }

            var url     = Feeds.FixtureFeed.GetFeedUrlByFixtureId(this.ApiFootballFixtureId);
            var rawJson = JsonUtility.GetRawJsonFromUrl(url);
            var feed    = Feeds.FixtureFeed.FromJson(rawJson);

            Feeds.FixtureFeed.ApiFixture feedFixture = feed.Result.Fixtures.SingleOrDefault();

            if (feedFixture == null)
            {
                return;
            }

            int dbFixtureId        = dbFixture.FixtureId;
            int dbHomeTeamSeasonId = dbFixture.HomeTeamSeasonId.Value;
            int dbAwayTeamSeasonId = dbFixture.AwayTeamSeasonId.Value;
            int apiAwayTeamId      = feedFixture.AwayTeam.TeamId;
            int apiHomeTeamId      = feedFixture.HomeTeam.TeamId;

            int?homeCoachId = null;
            int?awayCoachId = null;

            var apiPlayerBases     = GetApiPlayerBases(feedFixture);
            var dbPlayerSeasonDict = GetDbPlayerSeasonDict(dbContext, apiPlayerBases, dbFixture.CompetitionSeasonId);

            bool hasUpdate = false;

            Feeds.FixtureFeed.ApiLineup homeLineup = null;
            Feeds.FixtureFeed.ApiLineup awayLineup = null;

            #region GET FORMATIONS
            string homeFormation = null;
            string awayFormation = null;
            if (feedFixture.Lineups != null && feedFixture.Lineups.Count == 2)
            {
                string homeTeamName = feedFixture.HomeTeam.TeamName;
                string awayTeamName = feedFixture.AwayTeam.TeamName;

                // MISMATCH BETWEEN PLAYING TEAM NAMES AND LINEUP DICT KEYS HAS OCCURRED (API fixtureID: 188155)
                bool hasHomeTeamName = feedFixture.Lineups.Any(x => string.Equals(x.Key, homeTeamName, StringComparison.InvariantCultureIgnoreCase));
                bool hasAwayTeamName = feedFixture.Lineups.Any(x => string.Equals(x.Key, awayTeamName, StringComparison.InvariantCultureIgnoreCase));
                if (!hasHomeTeamName || !hasAwayTeamName)
                {
                    if (hasHomeTeamName && !hasAwayTeamName)
                    {
                        awayTeamName = feedFixture.Lineups.Keys.Single(x => !string.Equals(x, homeTeamName, StringComparison.InvariantCultureIgnoreCase));
                    }
                    else if (!hasHomeTeamName && hasAwayTeamName)
                    {
                        homeTeamName = feedFixture.Lineups.Keys.Single(x => !string.Equals(x, awayTeamName, StringComparison.InvariantCultureIgnoreCase));
                    }
                    else
                    {
                        throw new KeyNotFoundException("INVALID KEYS FOUND FOR FIXTURE LINEUPS");
                    }
                }

                homeLineup    = feedFixture.Lineups.Single(x => string.Equals(x.Key, homeTeamName, StringComparison.InvariantCultureIgnoreCase)).Value;
                awayLineup    = feedFixture.Lineups.Single(x => string.Equals(x.Key, awayTeamName, StringComparison.InvariantCultureIgnoreCase)).Value;
                homeFormation = homeLineup.Formation;
                awayFormation = awayLineup.Formation;
            }
            #endregion GET FORMATIONS

            #region ENSURE COACHES EXIST
            if (this.CheckEntitiesExist)
            {
                if (homeLineup != null || awayLineup != null)
                {
                    var apiCoachIds = new[] { homeLineup.CoachId, awayLineup.CoachId };
                    var dbCoaches   = dbContext.Coaches.Where(x => apiCoachIds.Contains(x.ApiFootballId)).ToDictionary(x => x.ApiFootballId, y => y);

                    if (homeLineup?.CoachId != null)
                    {
                        if (!dbCoaches.TryGetValue(homeLineup.CoachId.Value, out Coach dbHomeCoach))
                        {
                            dbHomeCoach = new Coach
                            {
                                ApiFootballId = homeLineup.CoachId.Value,
                                CoachName     = homeLineup.Coach
                            };
                            dbContext.Coaches.Add(dbHomeCoach);
                            dbContext.SaveChanges();
                            dbCoaches.Add(dbHomeCoach.CoachId, dbHomeCoach);                             // DUE TO BAD DATA, HOME COACH AND AWAY COACH MAY BE THE SAME (API GAME 126635)
                        }
                        homeCoachId = dbHomeCoach.CoachId;
                    }
                    if (awayLineup?.CoachId != null)
                    {
                        if (!dbCoaches.TryGetValue(awayLineup.CoachId.Value, out Coach dbAwayCoach))
                        {
                            dbAwayCoach = new Coach
                            {
                                ApiFootballId = awayLineup.CoachId.Value,
                                CoachName     = awayLineup.Coach
                            };
                            dbContext.Coaches.Add(dbAwayCoach);
                            dbContext.SaveChanges();
                        }
                        awayCoachId = dbAwayCoach.CoachId;
                    }
                }
            }
            #endregion ENSURE COACHES EXIST

            #region ENSURE PLAYERS EXIST
            if (this.CheckEntitiesExist)
            {
                var missingApiPlayerIds = apiPlayerBases?.Select(x => x.PlayerId).Where(x => !dbPlayerSeasonDict.ContainsKey(x)).ToList();
                if (missingApiPlayerIds != null && missingApiPlayerIds.Count > 0)
                {
                    foreach (var missingApiPlayerId in missingApiPlayerIds)
                    {
                        var apiPlayerBase = apiPlayerBases.Single(x => x.PlayerId == missingApiPlayerId);

                        var dbPlayer = dbContext.Players.SingleOrDefault(x => x.ApiFootballId == missingApiPlayerId);
                        if (dbPlayer == null)
                        {
                            dbPlayer = new Player
                            {
                                ApiFootballId   = missingApiPlayerId,
                                ApiFootballName = apiPlayerBase.PlayerName,
                                PlayerName      = apiPlayerBase.PlayerName
                            };
                        }

                        var dbPlayerSeason = new PlayerSeason
                        {
                            Player = dbPlayer,
                            CompetitionSeasonId = dbFixture.CompetitionSeasonId
                        };
                        dbContext.Add(dbPlayerSeason);
                    }
                    dbContext.SaveChanges();
                    dbPlayerSeasonDict = GetDbPlayerSeasonDict(dbContext, apiPlayerBases, dbFixture.CompetitionSeasonId);
                }
            }
            #endregion ENSURE PLAYERS EXIST

            #region UPDATE FORAMATION AND COACH IF NECESSARY
            if (homeCoachId.HasValue && dbFixture.HomeCoachId != homeCoachId)
            {
                dbFixture.HomeCoachId = homeCoachId;
                hasUpdate             = true;
            }
            if (awayCoachId.HasValue && dbFixture.AwayCoachId != awayCoachId)
            {
                dbFixture.AwayCoachId = awayCoachId;
                hasUpdate             = true;
            }
            if (!string.IsNullOrEmpty(homeFormation) && dbFixture.HomeFormation != homeFormation)
            {
                dbFixture.HomeFormation = homeFormation;
                hasUpdate = true;
            }
            if (!string.IsNullOrEmpty(awayFormation) && dbFixture.AwayFormation != awayFormation)
            {
                dbFixture.AwayFormation = awayFormation;
                hasUpdate = true;
            }
            #endregion UPDATE FORAMATION AND COACH IF NECESSARY

            #region FIXTURE EVENTS
            // HAVE EACH dbFixtureEvent AVAILABLE. ILookup IS AN IMMUTABLE TYPE, SO A DICTIONARY WITH THE COUNT IS ALSO NEEDED TO TRACK THE NUMBER OF OCCURANCES OF EACH EVENT.
            // THE ILookup IS JUST TO FIND FIND THE DB REFERENCE FOR EACH EVENT TO MANIPULATE
            var dbFixtureEventLookup            = dbContext.FixtureEvents.Where(x => x.FixtureId == dbFixtureId).ToLookup(x => GetFixtureEventKey(x));
            var dbFixtureEventToDeleteCountDict = dbContext.FixtureEvents.Where(x => x.FixtureId == dbFixtureId).ToList().GroupBy(x => GetFixtureEventKey(x)).ToDictionary(x => x.Key, y => y.Count());

            var apiFixtureEvents = feedFixture.Events?.Where(x => x.TeamId.HasValue).ToList();
            if (apiFixtureEvents != null && apiFixtureEvents.Count > 0)
            {
                foreach (var apiFixtureEvent in apiFixtureEvents)
                {
                    int dbTeamSeasonId   = apiFixtureEvent.TeamId == apiAwayTeamId ? dbAwayTeamSeasonId : dbHomeTeamSeasonId;
                    int?dbPlayerSeasonId = null;
                    if (dbPlayerSeasonDict != null && apiFixtureEvent.PlayerId.HasValue && dbPlayerSeasonDict.TryGetValue(apiFixtureEvent.PlayerId.Value, out int intPlayerSeasonId))
                    {
                        dbPlayerSeasonId = intPlayerSeasonId;
                    }
                    int?dbSecondaryPlayerSeasonId = null;
                    if (dbPlayerSeasonDict != null && apiFixtureEvent.SecondaryPlayerId.HasValue && dbPlayerSeasonDict.TryGetValue(apiFixtureEvent.SecondaryPlayerId.Value, out intPlayerSeasonId))
                    {
                        dbSecondaryPlayerSeasonId = intPlayerSeasonId;
                    }

                    // IT IS POSSIBLE TO HAVE MULTIPLE IDENTICAL EVENTS IN THE SAME MINUTE
                    // API FIXTURE ID 185030 - 2 GOALS BY SAME PLAYER IN SAME MINUTE
                    // USE LOOKUP TO DETERMINE CORRECT AMOUNT OF EXISTENCE
                    var          eventKey = GetFixtureEventKey(apiFixtureEvent.Elapsed, apiFixtureEvent.ElapsedPlus, dbPlayerSeasonId, dbTeamSeasonId, apiFixtureEvent.EventType, apiFixtureEvent.EventDetail);
                    var          dbCount  = dbFixtureEventToDeleteCountDict.TryGetValue(eventKey, out int tempInt) ? tempInt : 0;
                    FixtureEvent dbFixtureEvent;
                    if (dbCount == 0)
                    {
                        dbFixtureEvent = new FixtureEvent
                        {
                            EventComment            = apiFixtureEvent.EventComments,
                            EventDetail             = apiFixtureEvent.EventDetail,
                            EventType               = apiFixtureEvent.EventType,
                            FixtureId               = dbFixtureId,
                            EventTime               = apiFixtureEvent.Elapsed,
                            EventTimePlus           = apiFixtureEvent.ElapsedPlus,
                            PlayerSeasonId          = dbPlayerSeasonId,
                            SecondaryPlayerSeasonId = dbSecondaryPlayerSeasonId,
                            TeamSeasonId            = dbTeamSeasonId
                        };
                        dbContext.FixtureEvents.Add(dbFixtureEvent);
                        hasUpdate = true;
                    }
                    else
                    {
                        dbFixtureEvent = dbFixtureEventLookup[eventKey].Skip(dbCount - 1).First();                         // TAKE LAST ENTRY IN LOOKUP. AS THE COUNT IN THE dbFixtureEventCount DICTIONARY IS DECREMENTED, THE SELECTED EVENT WILL MOVE DOWN THE LIST
                        if (dbCount == 1)
                        {
                            dbFixtureEventToDeleteCountDict.Remove(eventKey);
                        }
                        else
                        {
                            dbFixtureEventToDeleteCountDict[eventKey] = dbCount - 1;
                        }

                        if ((!string.IsNullOrEmpty(apiFixtureEvent.EventComments) && dbFixtureEvent.EventComment != apiFixtureEvent.EventComments) ||
                            (!string.IsNullOrEmpty(apiFixtureEvent.EventDetail) && dbFixtureEvent.EventDetail != apiFixtureEvent.EventDetail) ||
                            (dbSecondaryPlayerSeasonId.HasValue && (!dbFixtureEvent.SecondaryPlayerSeasonId.HasValue || dbFixtureEvent.SecondaryPlayerSeasonId != dbSecondaryPlayerSeasonId)) ||
                            (!dbSecondaryPlayerSeasonId.HasValue && dbFixtureEvent.SecondaryPlayerSeasonId.HasValue))
                        {
                            dbFixtureEvent.EventComment            = apiFixtureEvent.EventComments;
                            dbFixtureEvent.EventDetail             = apiFixtureEvent.EventDetail;
                            dbFixtureEvent.SecondaryPlayerSeasonId = dbSecondaryPlayerSeasonId;
                            hasUpdate = true;
                        }
                    }
                }
                if (dbFixtureEventToDeleteCountDict.Count > 0)
                {
                    foreach (var dbFixtureEventCountEntry in dbFixtureEventToDeleteCountDict)
                    {
                        var dbFixtureEventLookupEntry = dbFixtureEventLookup[dbFixtureEventCountEntry.Key];
                        int dbFixtureEventCount       = dbFixtureEventLookupEntry.Count();
                        if (dbFixtureEventCount >= 1)
                        {
                            for (int i = dbFixtureEventCount; i >= 1; i--)
                            {
                                var dbFixtureEvent = dbFixtureEventLookupEntry.Skip(i - 1).First();
                                dbContext.FixtureEvents.Remove(dbFixtureEvent);
                            }
                        }
                    }
                    hasUpdate = true;
                }
            }
            #endregion FIXTURE EVENTS

            #region TEAM BOXSCORE

            var apiTeamStatsDict = feedFixture.TeamStatistics;
            if (apiTeamStatsDict == null)
            {
                if (!dbFixture.HasTeamBoxscores.HasValue || dbFixture.HasTeamBoxscores.Value)
                {
                    hasUpdate = true;
                }
                dbFixture.HasTeamBoxscores = false;
            }
            else
            {
                var dbTeamBoxscores = dbContext.TeamBoxscores.Where(x => x.FixtureId == dbFixtureId);

                var dbHomeBoxscore = dbTeamBoxscores?.SingleOrDefault(x => x.TeamSeasonId == dbHomeTeamSeasonId);
                var dbAwayBoxscore = dbTeamBoxscores?.SingleOrDefault(x => x.TeamSeasonId == dbAwayTeamSeasonId);

                if (dbHomeBoxscore == null)
                {
                    dbHomeBoxscore = new TeamBoxscore
                    {
                        FixtureId       = dbFixtureId,
                        TeamSeasonId    = dbHomeTeamSeasonId,
                        OppTeamSeasonId = dbAwayTeamSeasonId,
                        IsHome          = true
                    };
                    dbContext.TeamBoxscores.Add(dbHomeBoxscore);
                    hasUpdate = true;
                }
                if (dbAwayBoxscore == null)
                {
                    dbAwayBoxscore = new TeamBoxscore
                    {
                        FixtureId       = dbFixtureId,
                        TeamSeasonId    = dbAwayTeamSeasonId,
                        OppTeamSeasonId = dbHomeTeamSeasonId,
                        IsHome          = false,
                    };
                    dbContext.TeamBoxscores.Add(dbAwayBoxscore);
                    hasUpdate = true;
                }

                if (PopulateTeamBoxscore(apiTeamStatsDict, x => x.Home, ref dbHomeBoxscore))
                {
                    hasUpdate = true;
                    dbFixture.HasTeamBoxscores = true;
                }
                if (PopulateTeamBoxscore(apiTeamStatsDict, x => x.Away, ref dbAwayBoxscore))
                {
                    hasUpdate = true;
                    dbFixture.HasTeamBoxscores = true;
                }

                if (!dbFixture.HasTeamBoxscores.HasValue)
                {
                    dbFixture.HasTeamBoxscores = false;
                }
            }
            #endregion TEAM BOXSCORE

            #region PLAYER BOXSCORE
            if (apiPlayerBases != null && apiPlayerBases.Count > 0)
            {
                var dbPlayerBoxscores = dbContext.PlayerBoxscores
                                        .Include(x => x.PlayerSeason)
                                        .ThenInclude(y => y.Player)
                                        .Where(x => x.FixtureId == dbFixtureId && x.PlayerSeason != null && x.PlayerSeason.Player != null)
                                        .ToDictionary(x => x.PlayerSeason.Player.ApiFootballId, y => y);
                bool hasApiPlayerBoxscores = feedFixture?.PlayerBoxscores != null;
                bool hasApiLineups         = feedFixture?.AllLineupPlayers != null;
                foreach (var apiPlayerBase in apiPlayerBases)
                {
                    var dbPlayerSeasonId = dbPlayerSeasonDict[apiPlayerBase.PlayerId];
                    if (!dbPlayerBoxscores.TryGetValue(apiPlayerBase.PlayerId, out PlayerBoxscore dbPlayerBoxscore))
                    {
                        dbPlayerBoxscore = new PlayerBoxscore
                        {
                            PlayerSeasonId = dbPlayerSeasonId,
                            IsStarter      = apiPlayerBase.IsStarter,
                            FixtureId      = dbFixtureId,
                            TeamSeasonId   = apiPlayerBase.TeamId == feedFixture.HomeTeam.TeamId ? dbHomeTeamSeasonId : dbAwayTeamSeasonId
                        };
                        dbContext.PlayerBoxscores.Add(dbPlayerBoxscore);
                        hasUpdate = true;
                    }

                    if (hasApiPlayerBoxscores || hasApiLineups)
                    {
                        Feeds.FixtureFeed.ApiPlayerBoxscore apiPlayerBoxscore = null;
                        if (apiPlayerBase.BoxscorePlayerId.HasValue && apiPlayerBase.JerseyNumber.HasValue)
                        {
                            apiPlayerBoxscore = feedFixture.PlayerBoxscores.Where(x => x.PlayerId.HasValue).FirstOrDefault(x => x.Number == apiPlayerBase.JerseyNumber && x.TeamId == apiPlayerBase.TeamId);
                        }

                        Feeds.FixtureFeed.ApiLineupPlayerWithStarterStatus apiPlayerLineup = null;
                        if (apiPlayerBase.LineupPlayerId.HasValue && apiPlayerBase.JerseyNumber.HasValue)
                        {
                            apiPlayerLineup = feedFixture.AllLineupPlayers.Where(x => x.PlayerId.HasValue).FirstOrDefault(x => x.Number == apiPlayerBase.JerseyNumber && x.TeamId == apiPlayerBase.TeamId);
                        }

                        if (apiPlayerBoxscore != null || apiPlayerLineup != null)
                        {
                            if (PopulatePlayerBoxscore(apiPlayerBoxscore, apiPlayerLineup, ref dbPlayerBoxscore))
                            {
                                hasUpdate = true;
                            }
                        }
                    }
                }
            }
            #endregion PLAYER BOXSCORE

            if (hasUpdate)
            {
                dbContext.SaveChanges();
            }
        }