/// <summary> /// Updates GroupLocationHistorical for any group locations in groups that have data group history enabled /// </summary> /// <param name="context">The context.</param> public void UpdateGroupLocationHistorical(IJobExecutionContext context) { var rockContext = new RockContext(); var groupLocationHistoricalService = new GroupLocationHistoricalService(rockContext); var groupLocationService = new GroupLocationService(rockContext); var groupLocationsWithHistoryEnabledQuery = groupLocationService.Queryable().Where(a => a.Group.GroupType.EnableGroupHistory == true).AsNoTracking(); var groupLocationsHistoricalCurrentQuery = groupLocationHistoricalService.Queryable().Where(a => a.CurrentRowIndicator == true).AsNoTracking(); // Mark GroupLocationHistorical Rows as History ( CurrentRowIndicator = false, etc ) if any of the tracked field values change var groupLocationHistoricalNoLongerCurrentQuery = groupLocationsHistoricalCurrentQuery.Join( groupLocationsWithHistoryEnabledQuery, glh => glh.GroupLocationId, gl => gl.Id, (glh, gl) => new { GroupLocation = gl, GroupLocationHistorical = glh }) .Where(a => a.GroupLocation.GroupId != a.GroupLocationHistorical.GroupId || (a.GroupLocation.GroupLocationTypeValueId != a.GroupLocation.GroupLocationTypeValueId) || (a.GroupLocation.GroupLocationTypeValueId.HasValue && a.GroupLocation.GroupLocationTypeValue.Value != a.GroupLocationHistorical.GroupLocationTypeName) || a.GroupLocation.LocationId != a.GroupLocationHistorical.LocationId || a.GroupLocation.Location.ModifiedDateTime != a.GroupLocationHistorical.LocationModifiedDateTime || (a.GroupLocation.Schedules.Select(s => new { ScheduleId = s.Id, s.ModifiedDateTime }).Except(a.GroupLocationHistorical.GroupLocationHistoricalSchedules.Select(hs => new { hs.ScheduleId, ModifiedDateTime = hs.ScheduleModifiedDateTime }))).Any() ); var effectiveExpireDateTime = RockDateTime.Now; int groupLocationsLoggedToHistory = 0; int groupLocationsSaveToHistoryCurrent = 0; if (groupLocationHistoricalNoLongerCurrentQuery.Any()) { var groupLocationHistoricalNoLongerCurrent = groupLocationHistoricalNoLongerCurrentQuery.Select(a => a.GroupLocationHistorical).AsNoTracking(); groupLocationsLoggedToHistory = rockContext.BulkUpdate(groupLocationHistoricalNoLongerCurrent, glh => new GroupLocationHistorical { CurrentRowIndicator = false, ExpireDateTime = effectiveExpireDateTime }); } // Insert Group Locations (that have a group with GroupType.EnableGroupHistory) that don't have a CurrentRowIndicator row yet ( or don't have a CurrentRowIndicator because it was stamped with CurrentRowIndicator=false ) var groupLocationsToAddToHistoricalCurrentsQuery = groupLocationsWithHistoryEnabledQuery.Where(gl => !groupLocationsHistoricalCurrentQuery.Any(glh => glh.GroupLocationId == gl.Id)); if (groupLocationsToAddToHistoricalCurrentsQuery.Any()) { List <GroupLocationHistorical> groupLocationHistoricalCurrentsToInsert = groupLocationsToAddToHistoricalCurrentsQuery .Include(a => a.GroupLocationTypeValue) .Include(a => a.Location).ToList() .Select(gl => GroupLocationHistorical.CreateCurrentRowFromGroupLocation(gl, effectiveExpireDateTime)).ToList(); groupLocationsSaveToHistoryCurrent = groupLocationHistoricalCurrentsToInsert.Count(); // get the current max GroupLocatiionHistorical.Id to help narrow down which ones were inserted int groupLocationHistoricalStartId = groupLocationHistoricalService.Queryable().Max(a => ( int? )a.Id) ?? 0; rockContext.BulkInsert(groupLocationHistoricalCurrentsToInsert); // since we used BulkInsert, we'll need to go back and get the Ids and the associated GroupLocation's Schedules for the GroupLocationHistorical records that we just inserted var insertedGroupLocationHistoricalIdsWithSchedules = groupLocationHistoricalService.Queryable() .Where(a => a.Id > groupLocationHistoricalStartId && a.GroupLocation.Schedules.Any()).ToList() .Select(a => new { GroupLocationHistoricalId = a.Id, a.GroupLocation.Schedules }); List <GroupLocationHistoricalSchedule> groupLocationHistoricalScheduleCurrentsToInsert = new List <GroupLocationHistoricalSchedule>(); foreach (var insertedGroupLocationHistoricalIdWithSchedules in insertedGroupLocationHistoricalIdsWithSchedules) { foreach (Schedule schedule in insertedGroupLocationHistoricalIdWithSchedules.Schedules) { groupLocationHistoricalScheduleCurrentsToInsert.Add(new GroupLocationHistoricalSchedule { GroupLocationHistoricalId = insertedGroupLocationHistoricalIdWithSchedules.GroupLocationHistoricalId, ScheduleId = schedule.Id, ScheduleName = schedule.ToString(), ScheduleModifiedDateTime = schedule.ModifiedDateTime }); } } if (groupLocationHistoricalScheduleCurrentsToInsert.Any()) { rockContext.BulkInsert(groupLocationHistoricalScheduleCurrentsToInsert); } } if (groupLocationsLoggedToHistory > 0) { _jobStatusMessages.Add($"Logged {groupLocationsLoggedToHistory} {"group location history snapshot".PluralizeIf( groupLocationsLoggedToHistory != 0 )}"); } if (groupLocationsSaveToHistoryCurrent > 0) { int newGroupLocationsAddedToHistory = groupLocationsSaveToHistoryCurrent - groupLocationsLoggedToHistory; if (newGroupLocationsAddedToHistory > 0) { _jobStatusMessages.Add($"Added {newGroupLocationsAddedToHistory} new {"group location history snapshot".PluralizeIf( newGroupLocationsAddedToHistory != 0 )}"); } } }