Пример #1
0
        /// <summary>
        /// Processes the step type. Add steps for everyone in the dataview
        /// </summary>
        /// <param name="jobContext">The job context.</param>
        /// <param name="stepTypeView">The step type view.</param>
        /// <param name="minDaysBetweenSteps">The minimum days between steps.</param>
        /// <param name="addedResults">The added results.</param>
        /// <param name="updatedResults">The updated results.</param>
        /// <param name="errorMessages">The error message.</param>
        private void ProcessStepType(
            IJobExecutionContext jobContext,
            StepTypeView stepTypeView,
            int minDaysBetweenSteps,
            ConcurrentBag <int> addedResults,
            ConcurrentBag <int> updatedResults,
            out List <string> errorMessages)
        {
            errorMessages = new List <string>();
            var rockContextGetList = new RockContext();

            rockContextGetList.Database.CommandTimeout = SqlCommandTimeoutSeconds;

            // Steps are created with a status of "complete", so if we need to know the status id
            var stepStatusId = stepTypeView.CompletedStepStatusIds.FirstOrDefault();

            if (stepStatusId == default)
            {
                errorMessages.Add($"The Step Type with id {stepTypeView.StepTypeId} does not have a valid Complete Status to use");
                return;
            }

            // Get the dataview configured for the step type
            var dataViewService = new DataViewService(rockContextGetList);
            var dataview        = dataViewService.Get(stepTypeView.AutoCompleteDataViewId);

            if (dataview == null)
            {
                errorMessages.Add($"The dataview {stepTypeView.AutoCompleteDataViewId} for step type {stepTypeView.StepTypeId} did not resolve");
                return;
            }

            // We can use the dataview to get the person alias id query
            var dataViewGetQueryArgs = new DataViewGetQueryArgs
            {
                DbContext = rockContextGetList,
                DatabaseTimeoutSeconds = SqlCommandTimeoutSeconds
            };

            IQueryable <IEntity> dataviewQuery;

            try
            {
                dataviewQuery = dataview.GetQuery(dataViewGetQueryArgs);
            }
            catch (Exception ex)
            {
                errorMessages.Add(ex.Message);
                ExceptionLogService.LogException(ex);
                return;
            }

            if (dataviewQuery == null)
            {
                errorMessages.Add($"Generating a query for dataview {stepTypeView.AutoCompleteDataViewId} for step type {stepTypeView.StepTypeId} was not successful");
                return;
            }

            // This query contains person ids in the dataview
            var personIdQuery = dataviewQuery.AsNoTracking().Select(e => e.Id);

            // Get the query for people that cannot get a new step
            var personIdsThatCannotGetStepQuery = GetPersonIdsThatCannotGetStepQuery(rockContextGetList, stepTypeView, minDaysBetweenSteps);

            // Subtract the people that cannot get a new step
            personIdQuery = personIdQuery.Except(personIdsThatCannotGetStepQuery);

            // If there are prerequisites, then subtract the people that cannot get the step because of unmet prerequisites
            if (stepTypeView.PrerequisiteStepTypeIds.Any())
            {
                var personIdsThatHaveMetPrerequisitesQuery = GetPersonIdsThatHaveMetPrerequisitesQuery(rockContextGetList, stepTypeView);
                personIdQuery = personIdQuery.Intersect(personIdsThatHaveMetPrerequisitesQuery);
            }

            // Convert to person aliases ids
            var personAliasService = new PersonAliasService(rockContextGetList);
            var personInfoList     = personAliasService.GetPrimaryAliasQuery()
                                     .Where(a => personIdQuery.Contains(a.PersonId))
                                     .Select(a => new
            {
                PersonId       = a.PersonId,
                PrimaryAliasId = a.Id
            })
                                     .ToList();

            // Add or update steps for each of the remaining aliases that have met all the conditions
            var stepServiceGetList = new StepService(rockContextGetList);
            var now          = RockDateTime.Now;
            var addedCount   = 0;
            var updatedCount = 0;

            // Query for existing incomplete steps for the people
            var existingIncompleteStepIdsByPersonId = stepServiceGetList.Queryable()
                                                      .Where(s =>
                                                             s.StepTypeId == stepTypeView.StepTypeId &&
                                                             personIdQuery.Contains(s.PersonAlias.PersonId) &&
                                                             !s.CompletedDateTime.HasValue)
                                                      .Select(a => new
            {
                a.PersonAlias.PersonId,
                StepId = a.Id
            })
                                                      .ToList()
                                                      .GroupBy(a => a.PersonId)
                                                      .ToDictionary(
                k => k.Key,
                // just in case the Person is has more than one incomplete step for this step type, just use the latest one
                // it should clean it self up on subsequent runs since the other steps for this person wouldn't have been marked complete yet
                v => v.Max(s => s.StepId)
                );


            long totalCount    = personInfoList.Count;
            long progressCount = 0;

            foreach (var personIdInfo in personInfoList)
            {
                var personId             = personIdInfo.PersonId;
                var personPrimaryAliasId = personIdInfo.PrimaryAliasId;

                var existingStepId = existingIncompleteStepIdsByPersonId.GetValueOrNull(personId);

                using (var rockContextLoop = new RockContext())
                {
                    var  stepServiceLoop = new StepService(rockContextLoop);
                    Step step;
                    if (existingStepId.HasValue)
                    {
                        step = stepServiceLoop.Get(existingStepId.Value);
                    }
                    else
                    {
                        step = new Step
                        {
                            StepTypeId    = stepTypeView.StepTypeId,
                            Caption       = stepTypeView.Name,
                            StartDateTime = now,
                            PersonAliasId = personPrimaryAliasId
                        };
                    }

                    step.CompletedDateTime = now;
                    step.StepStatusId      = stepStatusId;

                    if (!existingStepId.HasValue)
                    {
                        stepServiceLoop.AddWithoutValidation(step);
                        addedCount++;
                    }
                    else
                    {
                        updatedCount++;
                    }

                    rockContextLoop.SaveChanges();
                }

                progressCount++;

                // Update the progress every 5 seconds
                if ((RockDateTime.Now - _lastProgressUpdate).TotalSeconds >= 5)
                {
                    try
                    {
                        jobContext.UpdateLastStatusMessage($"Processing {stepTypeView.Name } steps : {progressCount}/{totalCount}");
                    }
                    catch (Exception ex)
                    {
                        // ignore, but write to debug output
                        System.Diagnostics.Debug.WriteLine($"Error updating LastStatusMessage for ProcessStepType loop: {ex}");
                    }
                    finally
                    {
                        _lastProgressUpdate = RockDateTime.Now;
                    }
                }
            }

            addedResults.Add(addedCount);
            updatedResults.Add(updatedCount);
        }