예제 #1
0
        public override async Task ExecuteAsync(TaskExecutionContext ctx)
        {
            var count         = 0;
            var numDeleted    = 0;
            var numAdded      = 0;
            var numCategories = 0;
            var pageSize      = 500;
            var pageIndex     = -1;

            var categoryIds = ctx.Parameters.ContainsKey("CategoryIds")
                ? ctx.Parameters["CategoryIds"].ToIntArray()
                : null;

            // Hooks are enabled because search index needs to be updated.
            using (var scope = new DbContextScope(ctx: _productCategoryRepository.Context, autoDetectChanges: false, validateOnSave: false, hooksEnabled: true, autoCommit: false))
            {
                // Delete existing system mappings.
                var deleteQuery = _productCategoryRepository.Table.Where(x => x.IsSystemMapping);
                if (categoryIds != null)
                {
                    deleteQuery = deleteQuery.Where(x => categoryIds.Contains(x.CategoryId));
                }

                var pager = new FastPager <ProductCategory>(deleteQuery, pageSize);

                while (pager.ReadNextPage(out var mappings))
                {
                    if (ctx.CancellationToken.IsCancellationRequested)
                    {
                        return;
                    }

                    if (mappings.Any())
                    {
                        _productCategoryRepository.DeleteRange(mappings);
                        numDeleted += await scope.CommitAsync();
                    }
                }

                try
                {
                    _productCategoryRepository.Context.DetachEntities <ProductCategory>();
                }
                catch { }

                // Insert new product category mappings.
                var categoryQuery = _categoryRepository.TableUntracked.Expand(x => x.RuleSets);
                if (categoryIds != null)
                {
                    categoryQuery = categoryQuery.Where(x => categoryIds.Contains(x.Id));
                }

                var categories = await categoryQuery
                                 .Where(x => x.Published && !x.Deleted && x.RuleSets.Any(y => y.IsActive))
                                 .ToListAsync();

                numCategories = categories.Count;

                foreach (var category in categories)
                {
                    var ruleSetProductIds = new HashSet <int>();

                    ctx.SetProgress(++count, categories.Count, $"Add product mappings for category \"{category.Name.NaIfEmpty()}\".");

                    // Execute active rule sets and collect product ids.
                    foreach (var ruleSet in category.RuleSets.Where(x => x.IsActive))
                    {
                        if (ctx.CancellationToken.IsCancellationRequested)
                        {
                            return;
                        }

                        if (_ruleFactory.CreateExpressionGroup(ruleSet, _productRuleProvider) is SearchFilterExpression expression)
                        {
                            pageIndex = -1;
                            while (true)
                            {
                                // Do not touch searchResult.Hits. We only need the product identifiers.
                                var searchResult = _productRuleProvider.Search(new SearchFilterExpression[] { expression }, ++pageIndex, pageSize);
                                ruleSetProductIds.AddRange(searchResult.HitsEntityIds);

                                if (pageIndex >= (searchResult.TotalHitsCount / pageSize))
                                {
                                    break;
                                }
                            }
                        }
                    }

                    // Add mappings.
                    if (ruleSetProductIds.Any())
                    {
                        foreach (var chunk in ruleSetProductIds.Slice(500))
                        {
                            if (ctx.CancellationToken.IsCancellationRequested)
                            {
                                return;
                            }

                            foreach (var productId in chunk)
                            {
                                _productCategoryRepository.Insert(new ProductCategory
                                {
                                    ProductId       = productId,
                                    CategoryId      = category.Id,
                                    IsSystemMapping = true
                                });

                                ++numAdded;
                            }

                            await scope.CommitAsync();
                        }

                        try
                        {
                            _productCategoryRepository.Context.DetachEntities <ProductCategory>();
                        }
                        catch { }
                    }
                }
            }

            Debug.WriteLineIf(numDeleted > 0 || numAdded > 0, $"Deleted {numDeleted} and added {numAdded} product mappings for {numCategories} categories.");
        }