protected virtual async Task <IDictionary <string, Category> > PreloadCategoriesAsync(string catalogId)
        {
            var cacheKey = CacheKey.With(GetType(), "PreloadCategories", catalogId);

            return(await _platformMemoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());

                CategoryEntity[] entities;
                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();

                    entities = await repository.GetCategoriesByIdsAsync(repository.Categories.Select(x => x.Id).ToArray(), CategoryResponseGroup.Full);
                }
                var result = entities.Select(x => x.ToModel(AbstractTypeFactory <Category> .TryCreateInstance()))
                             .ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase)
                             .WithDefaultValue(null);

                await LoadDependenciesAsync(result.Values, result);
                ApplyInheritanceRules(result.Values);

                // Fill outlines for categories
                _outlineService.FillOutlinesForObjects(result.Values, catalogId);
                return result;
            }));
        }
Exemple #2
0
        protected virtual Task <IDictionary <string, Catalog> > PreloadCatalogs()
        {
            var cacheKey = CacheKey.With(GetType(), "AllCatalogs");

            return(_platformMemoryCache.GetOrCreateExclusive(cacheKey, async(cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                CatalogEntity[] entities;
                using (var repository = _repositoryFactory())
                {
                    //Optimize performance and CPU usage
                    repository.DisableChangesTracking();

                    var ids = await repository.Catalogs.Select(x => x.Id).ToArrayAsync();
                    entities = await repository.GetCatalogsByIdsAsync(ids);
                }

                var result = entities.Select(x => x.ToModel(AbstractTypeFactory <Catalog> .TryCreateInstance()))
                             .ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase)
                             .WithDefaultValue(null);

                LoadDependencies(result.Values, result);
                return result;
            }));
        }
        public async Task DeleteAsync(IEnumerable <string> ids, bool doDeleteValues = false)
        {
            using (var repository = _repositoryFactory())
            {
                var entities = await repository.GetPropertiesByIdsAsync(ids.ToArray());

                //Raise domain events before deletion
                var changedEntries = entities.Select(x => new GenericChangedEntry <Property>(x.ToModel(AbstractTypeFactory <Property> .TryCreateInstance()), EntryState.Deleted));

                await _eventPublisher.Publish(new PropertyChangingEvent(changedEntries));

                foreach (var entity in entities)
                {
                    repository.Remove(entity);
                    if (doDeleteValues)
                    {
                        await repository.RemoveAllPropertyValuesAsync(entity.Id);
                    }
                }
                await repository.UnitOfWork.CommitAsync();

                await _eventPublisher.Publish(new PropertyChangedEvent(changedEntries));

                //Reset catalog cache
                CatalogCacheRegion.ExpireRegion();
            }
        }
Exemple #4
0
        protected virtual Dictionary <string, Category> PreloadCategories(string catalogId)
        {
            var cacheKey = CacheKey.With(GetType(), "PreloadCategories", catalogId);

            return(_memoryCache.GetOrCreateExclusive(cacheKey, (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                CategoryEntity[] entities;
                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();

                    entities = repository.GetCategoriesByIds(repository.Categories.Select(x => x.Id).ToArray());
                }
                var result = entities.Select(x => x.ToModel(AbstractTypeFactory <Category> .TryCreateInstance())).ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase);

                LoadDependencies(result.Values, result);
                ApplyInheritanceRules(result.Values.OrderBy(x => x.Level));

                // Fill outlines for categories
                _outlineService.FillOutlinesForObjects(result.Values, catalogId);

                var objectsWithSeo = new List <ISeoSupport>(result.Values);
                var outlineItems = result.Values.Where(c => c.Outlines != null).SelectMany(c => c.Outlines.SelectMany(o => o.Items));
                objectsWithSeo.AddRange(outlineItems);
                //TODO: convert to async
                _seoService.LoadSeoForObjectsAsync(objectsWithSeo.ToArray());
                return result;
            }));
        }
        public virtual async Task <CatalogProduct[]> GetByIdsAsync(string[] itemIds, string respGroup, string catalogId = null)
        {
            var itemResponseGroup = EnumUtility.SafeParseFlags(respGroup, ItemResponseGroup.ItemLarge);

            var cacheKey = CacheKey.With(GetType(), nameof(GetByIdsAsync), string.Join("-", itemIds), itemResponseGroup.ToString(), catalogId);
            var result   = await _platformMemoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                var products = Array.Empty <CatalogProduct>();

                if (!itemIds.IsNullOrEmpty())
                {
                    using (var repository = _repositoryFactory())
                    {
                        //Optimize performance and CPU usage
                        repository.DisableChangesTracking();

                        //It is so important to generate change tokens for all ids even for not existing objects to prevent an issue
                        //with caching of empty results for non - existing objects that have the infinitive lifetime in the cache
                        //and future unavailability to create objects with these ids.
                        cacheEntry.AddExpirationToken(ItemCacheRegion.CreateChangeToken(itemIds));
                        cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());

                        products = (await repository.GetItemByIdsAsync(itemIds, respGroup))
                                   .Select(x => x.ToModel(AbstractTypeFactory <CatalogProduct> .TryCreateInstance()))
                                   .ToArray();
                    }

                    if (products.Any())
                    {
                        products = products.OrderBy(x => Array.IndexOf(itemIds, x.Id)).ToArray();
                        await LoadDependenciesAsync(products);
                        ApplyInheritanceRules(products);

                        var productsWithVariationsList = products.Concat(products.Where(p => p.Variations != null)
                                                                         .SelectMany(p => p.Variations)).ToArray();

                        // Fill outlines for products and variations
                        if (itemResponseGroup.HasFlag(ItemResponseGroup.Outlines))
                        {
                            _outlineService.FillOutlinesForObjects(productsWithVariationsList, catalogId);
                        }
                        //Add change tokens for products with variations
                        cacheEntry.AddExpirationToken(ItemCacheRegion.CreateChangeToken(productsWithVariationsList));

                        //Reduce details according to response group
                        foreach (var product in productsWithVariationsList)
                        {
                            product.ReduceDetails(itemResponseGroup.ToString());
                        }
                    }
                }

                return(products);
            });

            return(result.Select(x => x.Clone() as CatalogProduct).ToArray());
        }
        /// <summary>
        /// Async search products by given criteria
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public virtual async Task <CatalogSearchResult> SearchProductsAsync(ProductSearchCriteria criteria)
        {
            var workContext = _workContextAccessor.WorkContext;
            var cacheKey    = CacheKey.With(GetType(), "SearchProductsAsync", criteria.GetCacheKey(), workContext.CurrentStore.Id, workContext.CurrentLanguage.CultureName, workContext.CurrentCurrency.Code);

            return(await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());

                criteria = criteria.Clone();

                var searchCriteria = criteria.ToProductSearchCriteriaDto(workContext);
                var result = await _searchApi.SearchProductsAsync(searchCriteria);
                var products = result.Items?.Select(x => x.ToProduct(workContext.CurrentLanguage, workContext.CurrentCurrency, workContext.CurrentStore)).ToList() ?? new List <Product>();

                if (products.Any())
                {
                    var productsWithVariations = products.Concat(products.SelectMany(x => x.Variations)).ToList();
                    var taskList = new List <Task>();

                    if (criteria.ResponseGroup.HasFlag(ItemResponseGroup.Inventory))
                    {
                        taskList.Add(LoadProductInventoriesAsync(productsWithVariations, workContext));
                    }

                    if (criteria.ResponseGroup.HasFlag(ItemResponseGroup.ItemAssociations))
                    {
                        taskList.Add(LoadProductsAssociationsAsync(productsWithVariations, workContext));
                    }

                    if (criteria.ResponseGroup.HasFlag(ItemResponseGroup.ItemWithVendor))
                    {
                        taskList.Add(LoadProductVendorsAsync(productsWithVariations, workContext));
                    }

                    if (criteria.ResponseGroup.HasFlag(ItemResponseGroup.ItemWithPrices))
                    {
                        taskList.Add(_pricingService.EvaluateProductPricesAsync(productsWithVariations, workContext));
                    }

                    await Task.WhenAll(taskList.ToArray());

                    foreach (var product in productsWithVariations)
                    {
                        product.IsBuyable = new ProductIsBuyableSpecification().IsSatisfiedBy(product);
                        product.IsAvailable = new ProductIsAvailableSpecification(product).IsSatisfiedBy(1);
                        product.IsInStock = new ProductIsInStockSpecification().IsSatisfiedBy(product);
                    }
                }
                return new CatalogSearchResult
                {
                    Products = new StaticPagedList <Product>(products, criteria.PageNumber, criteria.PageSize, (int?)result.TotalCount ?? 0),
                    Aggregations = !result.Aggregations.IsNullOrEmpty() ? result.Aggregations.Select(x => x.ToAggregation(workContext.CurrentLanguage.CultureName)).ToArray() : new Aggregation[] { }
                };
            }));
        }
Exemple #7
0
        protected virtual async Task <Product[]> GetProductsAsync(IList <string> ids, ItemResponseGroup responseGroup, WorkContext workContext)
        {
            var cacheKey = CacheKey.With(GetType(), "GetProductsAsync", string.Join("-", ids.OrderBy(x => x)), responseGroup.ToString());
            var result   = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());

                return(await _productsApi.GetProductByPlentyIdsAsync(ids, ((int)responseGroup).ToString()));
            });

            return(result.Select(x => x.ToProduct(workContext.CurrentLanguage, workContext.CurrentCurrency, workContext.CurrentStore)).ToArray());
        }
Exemple #8
0
        private async Task <Category[]> InnerGetCategoriesAsync(string[] ids, WorkContext workContext, CategoryResponseGroup responseGroup = CategoryResponseGroup.Info)
        {
            var cacheKey      = CacheKey.With(GetType(), "InnerGetCategoriesAsync", string.Join("-", ids.OrderBy(x => x)), responseGroup.ToString());
            var categoriesDto = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                return(await _categoriesApi.GetCategoriesByPlentyIdsAsync(ids.ToList(), ((int)responseGroup).ToString()));
            });

            var result = categoriesDto.Select(x => x.ToCategory(workContext.CurrentLanguage, workContext.CurrentStore)).ToArray();

            //Set  lazy loading for child categories
            SetChildCategoriesLazyLoading(result);
            return(result);
        }
Exemple #9
0
        protected virtual async Task <catalogDto.ProductSearchResult> SearchProductsAsync(ProductSearchCriteria criteria, WorkContext workContext)
        {
            var cacheKey = CacheKey.With(GetType(), "SearchProductsAsync", criteria.GetCacheKey(), workContext.CurrentStore.Id, workContext.CurrentLanguage.CultureName, workContext.CurrentCurrency.Code);

            return(await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());

                criteria = criteria.Clone() as ProductSearchCriteria;

                var searchCriteria = criteria.ToProductSearchCriteriaDto(workContext);
                return await _searchApi.SearchProductsAsync(searchCriteria);
            }));
        }
Exemple #10
0
        protected virtual Task LoadProductsAssociationsAsync(IEnumerable <Product> products, WorkContext workContext)
        {
            if (products == null)
            {
                throw new ArgumentNullException(nameof(products));
            }

            foreach (var product in products)
            {
                //Associations
                product.Associations = new MutablePagedList <ProductAssociation>((pageNumber, pageSize, sortInfos, @params) =>
                {
                    var criteria = new ProductAssociationSearchCriteria
                    {
                        PageNumber    = pageNumber,
                        PageSize      = pageSize,
                        ProductId     = product.Id,
                        ResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemWithPrices | ItemResponseGroup.Inventory | ItemResponseGroup.ItemWithVendor
                    };
                    if (!sortInfos.IsNullOrEmpty())
                    {
                        criteria.Sort = SortInfo.ToString(sortInfos);
                    }
                    if (@params != null)
                    {
                        criteria.CopyFrom(@params);
                    }
                    var cacheKey     = CacheKey.With(GetType(), "SearchProductAssociations", criteria.GetCacheKey());
                    var searchResult = _memoryCache.GetOrCreateExclusive(cacheKey, cacheEntry =>
                    {
                        cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                        cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());
                        return(_productsApi.SearchProductAssociations(criteria.ToProductAssociationSearchCriteriaDto()));
                    });
                    //Load products for resulting associations
                    var associatedProducts = GetProductsAsync(searchResult.Results.Select(x => x.AssociatedObjectId).ToArray(), criteria.ResponseGroup).GetAwaiter().GetResult();
                    var result             = new List <ProductAssociation>();
                    foreach (var associationDto in searchResult.Results)
                    {
                        var productAssociation     = associationDto.ToProductAssociation();
                        productAssociation.Product = associatedProducts.FirstOrDefault(x => x.Id.EqualsInvariant(productAssociation.ProductId));
                        result.Add(productAssociation);
                    }
                    return(new StaticPagedList <ProductAssociation>(result, pageNumber, pageSize, searchResult.TotalCount ?? 0));
                }, 1, ProductSearchCriteria.DefaultPageSize);
            }
            return(Task.CompletedTask);
        }
Exemple #11
0
        public virtual async Task <Category[]> GetCategoriesAsync(string[] ids, CategoryResponseGroup responseGroup = CategoryResponseGroup.Info)
        {
            var workContext   = _workContextAccessor.WorkContext;
            var cacheKey      = CacheKey.With(GetType(), "GetCategoriesAsync", string.Join("-", ids.OrderBy(x => x)), responseGroup.ToString());
            var categoriesDto = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                return(await _categoriesApi.GetCategoriesByPlentyIdsAsync(ids.ToList(), ((int)responseGroup).ToString()));
            });

            var result = categoriesDto.Select(x => x.ToCategory(workContext.CurrentLanguage, workContext.CurrentStore)).ToArray();

            //Set  lazy loading for child categories
            EstablishLazyDependenciesForCategories(result);
            return(result);
        }
        public async Task SaveChangesAsync(IEnumerable <Property> properties)
        {
            var pkMap          = new PrimaryKeyResolvingMap();
            var changedEntries = new List <GenericChangedEntry <Property> >();

            ValidateProperties(properties);

            using (var repository = _repositoryFactory())
            {
                TryAddPredefinedValidationRules(properties);

                var dbExistProperties = await repository.GetPropertiesByIdsAsync(properties.Where(x => !x.IsTransient()).Select(x => x.Id).ToArray());

                foreach (var property in properties)
                {
                    var modifiedEntity = AbstractTypeFactory <PropertyEntity> .TryCreateInstance().FromModel(property, pkMap);

                    var originalEntity = dbExistProperties.FirstOrDefault(x => x.Id == property.Id);

                    if (originalEntity != null)
                    {
                        changedEntries.Add(new GenericChangedEntry <Property>(property, originalEntity.ToModel(AbstractTypeFactory <Property> .TryCreateInstance()), EntryState.Modified));
                        modifiedEntity.Patch(originalEntity);
                        //Force set ModifiedDate property to mark a product changed. Special for  partial update cases when product table not have changes
                        originalEntity.ModifiedDate = DateTime.UtcNow;
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                        changedEntries.Add(new GenericChangedEntry <Property>(property, EntryState.Added));
                    }
                }

                //Raise domain events
                await _eventPublisher.Publish(new PropertyChangingEvent(changedEntries));

                //Save changes in database
                await repository.UnitOfWork.CommitAsync();

                pkMap.ResolvePrimaryKeys();

                //Reset catalog cache
                CatalogCacheRegion.ExpireRegion();

                await _eventPublisher.Publish(new PropertyChangedEvent(changedEntries));
            }
        }
Exemple #13
0
        public void Delete(IEnumerable <string> catalogIds)
        {
            var catalogs = GetByIds(catalogIds);
            //Raise domain events before deletion
            var changedEntries = catalogs.Select(x => new GenericChangedEntry <Catalog>(x, EntryState.Deleted));

            _eventPublisher.Publish(new CatalogChangingEvent(changedEntries));
            using (var repository = _repositoryFactory())
            {
                //TODO:  raise events on catalog deletion
                repository.RemoveCatalogs(catalogIds.ToArray());
                repository.UnitOfWork.Commit();
                //Reset cached catalogs and catalogs
                CatalogCacheRegion.ExpireRegion();
            }
            _eventPublisher.Publish(new CatalogChangedEvent(changedEntries));
        }
        public virtual async Task <CatalogProduct[]> GetByIdsAsync(string[] itemIds, string responseGroup, string catalogId = null)
        {
            var itemResponseGroup = EnumUtility.SafeParseFlags(responseGroup, ItemResponseGroup.ItemLarge);

            var cacheKey = CacheKey.With(GetType(), "GetByIdsAsync", string.Join("-", itemIds), itemResponseGroup.ToString(), catalogId);

            return(await _platformMemoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                CatalogProduct[] result;

                using (var repository = _repositoryFactory())
                {
                    //Optimize performance and CPU usage
                    repository.DisableChangesTracking();

                    result = (await repository.GetItemByIdsAsync(itemIds, itemResponseGroup))
                             .Select(x => x.ToModel(AbstractTypeFactory <CatalogProduct> .TryCreateInstance()))
                             .ToArray();
                }

                await LoadDependenciesAsync(result);

                var productsWithVariationsList = result.Concat(result.Where(p => p.Variations != null)
                                                               .SelectMany(p => p.Variations)).ToArray();
                ApplyInheritanceRules(productsWithVariationsList);


                // Fill outlines for products and variations
                if (itemResponseGroup.HasFlag(ItemResponseGroup.Outlines))
                {
                    _outlineService.FillOutlinesForObjects(productsWithVariationsList, catalogId);
                }


                //Reduce details according to response group
                foreach (var product in productsWithVariationsList)
                {
                    product.ReduceDetails(itemResponseGroup.ToString());
                    cacheEntry.AddExpirationToken(ItemCacheRegion.CreateChangeToken(product));
                    cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                }

                return result;
            }));
        }
Exemple #15
0
        public virtual async Task DeleteAsync(string[] catalogIds)
        {
            using (var repository = _repositoryFactory())
            {
                var catalogs = await GetByIdsAsync(catalogIds);

                if (!catalogs.IsNullOrEmpty())
                {
                    var changedEntries = catalogs.Select(x => new GenericChangedEntry <Catalog>(x, EntryState.Deleted));
                    await _eventPublisher.Publish(new CatalogChangingEvent(changedEntries));

                    await repository.RemoveCatalogsAsync(catalogs.Select(m => m.Id).ToArray());

                    await repository.UnitOfWork.CommitAsync();

                    await _eventPublisher.Publish(new CatalogChangedEvent(changedEntries));
                }
            }
            CatalogCacheRegion.ExpireRegion();
        }
        public ActionResult ResetCache()
        {
            //TODO: Replace to some other (maybe with using reflection)
            ThemeEngineCacheRegion.ExpireRegion();
            CartCacheRegion.ExpireRegion();
            CatalogCacheRegion.ExpireRegion();
            ContentBlobCacheRegion.ExpireRegion();
            CustomerCacheRegion.ExpireRegion();
            MarketingCacheRegion.ExpireRegion();
            PricingCacheRegion.ExpireRegion();
            QuoteCacheRegion.ExpireRegion();
            RecommendationsCacheRegion.ExpireRegion();
            StaticContentCacheRegion.ExpireRegion();
            StoreCacheRegion.ExpireRegion();
            TaxCacheRegion.ExpireRegion();
            SubscriptionCacheRegion.ExpireRegion();
            SecurityCacheRegion.ExpireRegion();

            return(StoreFrontRedirect("~/"));
        }
        public virtual async Task DeleteAsync(string[] categoryIds)
        {
            var categories = await GetByIdsAsync(categoryIds, CategoryResponseGroup.Info.ToString());

            var changedEntries = categories
                                 .Select(c => new GenericChangedEntry <Category>(c, EntryState.Deleted))
                                 .ToList();

            using (var repository = _repositoryFactory())
            {
                await _eventPublisher.Publish(new CategoryChangingEvent(changedEntries));

                await repository.RemoveCategoriesAsync(categoryIds);

                await repository.UnitOfWork.CommitAsync();

                CatalogCacheRegion.ExpireRegion();
                await _eventPublisher.Publish(new CategoryChangedEvent(changedEntries));
            }
        }
Exemple #18
0
        public virtual void SaveChanges(IEnumerable <Category> categories)
        {
            var pkMap          = new PrimaryKeyResolvingMap();
            var changedEntries = new List <GenericChangedEntry <Category> >();

            ValidateCategoryProperties(categories);

            using (var repository = _repositoryFactory())
            {
                var dbExistCategories = repository.GetCategoriesByIds(categories.Where(x => !x.IsTransient()).Select(x => x.Id).ToArray());
                foreach (var category in categories)
                {
                    var originalEntity = dbExistCategories.FirstOrDefault(x => x.Id == category.Id);
                    var modifiedEntity = AbstractTypeFactory <CategoryEntity> .TryCreateInstance().FromModel(category, pkMap);

                    if (originalEntity != null)
                    {
                        changedEntries.Add(new GenericChangedEntry <Category>(category, originalEntity.ToModel(AbstractTypeFactory <Category> .TryCreateInstance()), EntryState.Modified));
                        modifiedEntity.Patch(originalEntity);
                        //Force set ModifiedDate property to mark a product changed. Special for  partial update cases when product table not have changes
                        originalEntity.ModifiedDate = DateTime.UtcNow;
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                        changedEntries.Add(new GenericChangedEntry <Category>(category, EntryState.Added));
                    }
                }

                //Raise domain events
                _eventPublisher.Publish(new CategoryChangingEvent(changedEntries));
                //Save changes in database
                repository.UnitOfWork.Commit();
                pkMap.ResolvePrimaryKeys();
                _eventPublisher.Publish(new CategoryChangedEvent(changedEntries));
                //Reset catalog cache
                CatalogCacheRegion.ExpireRegion();
            }
            //Need add seo separately
            _seoService.SaveSeoForObjectsAsync(categories.OfType <ISeoSupport>().ToArray());
        }
        public virtual async Task SaveChangesAsync(Catalog[] catalogs)
        {
            var pkMap          = new PrimaryKeyResolvingMap();
            var changedEntries = new List <GenericChangedEntry <Catalog> >();

            using (var repository = _repositoryFactory())
            {
                await ValidateCatalogPropertiesAsync(catalogs);

                var dbExistEntities = await repository.GetCatalogsByIdsAsync(catalogs.Where(x => !x.IsTransient()).Select(x => x.Id).ToArray());

                foreach (var catalog in catalogs)
                {
                    var originalEntity = dbExistEntities.FirstOrDefault(x => x.Id == catalog.Id);
                    var modifiedEntity = AbstractTypeFactory <CatalogEntity> .TryCreateInstance().FromModel(catalog, pkMap);

                    if (originalEntity != null)
                    {
                        changedEntries.Add(new GenericChangedEntry <Catalog>(catalog, originalEntity.ToModel(AbstractTypeFactory <Catalog> .TryCreateInstance()), EntryState.Modified));
                        modifiedEntity.Patch(originalEntity);
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                        changedEntries.Add(new GenericChangedEntry <Catalog>(catalog, EntryState.Added));
                    }
                }
                //Raise domain events
                await _eventPublisher.Publish(new CatalogChangingEvent(changedEntries));

                //Save changes in database
                await repository.UnitOfWork.CommitAsync();

                pkMap.ResolvePrimaryKeys();

                //Reset cached catalogs and catalogs
                CatalogCacheRegion.ExpireRegion();

                await _eventPublisher.Publish(new CatalogChangedEvent(changedEntries));
            }
        }
        public virtual async Task SaveChangesAsync(Category[] categories)
        {
            var pkMap          = new PrimaryKeyResolvingMap();
            var changedEntries = new List <GenericChangedEntry <Category> >();

            await ValidateCategoryPropertiesAsync(categories);

            using (var repository = _repositoryFactory())
            {
                var dbExistCategories = await repository.GetCategoriesByIdsAsync(categories.Where(x => !x.IsTransient()).Select(x => x.Id).ToArray(), CategoryResponseGroup.Full);

                foreach (var category in categories)
                {
                    var originalEntity = dbExistCategories.FirstOrDefault(x => x.Id == category.Id);
                    var modifiedEntity = AbstractTypeFactory <CategoryEntity> .TryCreateInstance().FromModel(category, pkMap);

                    if (originalEntity != null)
                    {
                        changedEntries.Add(new GenericChangedEntry <Category>(category, originalEntity.ToModel(AbstractTypeFactory <Category> .TryCreateInstance()), EntryState.Modified));
                        modifiedEntity.Patch(originalEntity);
                        //Force set ModifiedDate property to mark a product changed. Special for  partial update cases when product table not have changes
                        originalEntity.ModifiedDate = DateTime.UtcNow;
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                        changedEntries.Add(new GenericChangedEntry <Category>(category, EntryState.Added));
                    }
                }

                await _eventPublisher.Publish(new CategoryChangingEvent(changedEntries));

                await repository.UnitOfWork.CommitAsync();

                pkMap.ResolvePrimaryKeys();
                CatalogCacheRegion.ExpireRegion();

                await _eventPublisher.Publish(new CategoryChangedEvent(changedEntries));
            }
        }
        public Task <PropertyDictionaryItem[]> GetByIdsAsync(string[] ids)
        {
            var cacheKey = CacheKey.With(GetType(), "GetByIdsAsync", string.Join(",", ids));

            return(_platformMemoryCache.GetOrCreateExclusive(cacheKey, async(cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(DictionaryItemsCacheRegion.CreateChangeToken());
                PropertyDictionaryItem[] result;

                using (var repository = _repositoryFactory())
                {
                    //Optimize performance and CPU usage
                    repository.DisableChangesTracking();

                    result = (await repository.GetPropertyDictionaryItemsByIdsAsync(ids))
                             .Select(x => x.ToModel(AbstractTypeFactory <PropertyDictionaryItem> .TryCreateInstance()))
                             .ToArray();
                }
                return result;
            }));
        }
Exemple #22
0
        protected virtual IDictionary <string, Property> PreloadAllProperties()
        {
            var cacheKey = CacheKey.With(GetType(), "PreloadAllProperties");

            return(_memoryCache.GetOrCreateExclusive(cacheKey, (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();

                    var propertyIds = repository.Properties.Select(p => p.Id).ToArray();
                    var entities = repository.GetPropertiesByIds(propertyIds);
                    var properties = entities.Select(p => p.ToModel(AbstractTypeFactory <Property> .TryCreateInstance())).ToArray();

                    LoadDependencies(properties);
                    ApplyInheritanceRules(properties);
                    var result = properties.ToDictionary(p => p.Id, StringComparer.OrdinalIgnoreCase);
                    return result;
                }
            }));
        }
        protected virtual async Task <Property[]> PreloadAllCatalogPropertiesAsync(string catalogId)
        {
            var cacheKey = CacheKey.With(GetType(), "PreloadAllCatalogProperties", catalogId);

            return(await _platformMemoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                using (var repository = _repositoryFactory())
                {
                    repository.DisableChangesTracking();

                    var result = (await repository.GetAllCatalogPropertiesAsync(catalogId))
                                 .GroupBy(p => p.Id, StringComparer.OrdinalIgnoreCase) // Remove duplicates
                                 .Select(g => g.First())
                                 .OrderBy(p => p.Name, StringComparer.OrdinalIgnoreCase)
                                 .Select(p => p.ToModel(AbstractTypeFactory <Property> .TryCreateInstance()))
                                 .ToArray();

                    return result;
                }
            }));
        }
        public async Task <ProductPart[]> GetProductPartsAsync(string productId)
        {
            var workContext = _workContextAccessor.WorkContext;
            var cacheKey    = CacheKey.With(GetType(), nameof(GetProductPartsAsync), productId);

            var searchResult = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());
                var searchPartsResultDto = await _demoCatalogApi.SearchAsync(new DemoProductPartSearchCriteria {
                    ConfiguredProductId = productId, Take = int.MaxValue
                });
                return(searchPartsResultDto);
            });

            var partItemIds = searchResult.Results?
                              .Where(x => x.PartItems != null).SelectMany(x => x.PartItems).Select(x => x.ItemId).Distinct()
                              .ToArray();

            var allPartItems = !partItemIds.IsNullOrEmpty() ? await GetProductsAsync(partItemIds) : null; // Potential recursion

            ProductPart ConvertDtoToProductPartAndAttachItsItems(DemoProductPart x, WorkContext workContext, Product[] allPartItems)
            {
                var productPart = x.ToProductPart(workContext.CurrentLanguage.CultureName);

                productPart.Items = x.PartItems?
                                    .OrderBy(partItemInfo => partItemInfo.Priority)
                                    .Select(partItemInfo => allPartItems?.FirstOrDefault(product => product.Id.EqualsInvariant(partItemInfo.ItemId)))
                                    .Where(product => product != null)
                                    .ToArray() ?? Array.Empty <Product>();
                return(productPart);
            }

            var productParts = searchResult.Results?.OrderBy(x => x.Priority).Select(x => ConvertDtoToProductPartAndAttachItsItems(x, workContext, allPartItems))
                               .ToArray <ProductPart>() ?? Array.Empty <ProductPart>();

            return(productParts);
        }
Exemple #25
0
        private async Task <IPagedList <Category> > InnerSearchCategoriesAsync(CategorySearchCriteria criteria, WorkContext workContext)
        {
            var cacheKey     = CacheKey.With(GetType(), "InnerSearchCategoriesAsync", criteria.GetCacheKey(), workContext.CurrentStore.Id, workContext.CurrentLanguage.CultureName, workContext.CurrentCurrency.Code);
            var searchResult = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());

                criteria           = criteria.Clone();
                var searchCriteria = criteria.ToCategorySearchCriteriaDto(workContext);
                return(await _searchApi.SearchCategoriesAsync(searchCriteria));
            });

            var result = new PagedList <Category>(new List <Category>().AsQueryable(), 1, 1);

            if (searchResult.Items != null)
            {
                result = new PagedList <Category>(searchResult.Items.Select(x => x.ToCategory(workContext.CurrentLanguage, workContext.CurrentStore)).AsQueryable(), criteria.PageNumber, criteria.PageSize);
            }
            //Set  lazy loading for child categories
            SetChildCategoriesLazyLoading(result.ToArray());
            return(result);
        }
        /// <summary>
        /// Async search categories by given criteria
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public virtual async Task <IPagedList <Category> > SearchCategoriesAsync(CategorySearchCriteria criteria)
        {
            var workContext  = _workContextAccessor.WorkContext;
            var cacheKey     = CacheKey.With(GetType(), nameof(SearchCategoriesAsync), criteria.GetCacheKey(), workContext.CurrentStore.Id, workContext.CurrentLanguage.CultureName, workContext.CurrentCurrency.Code);
            var searchResult = await _memoryCache.GetOrCreateExclusiveAsync(cacheKey, async (cacheEntry) =>
            {
                cacheEntry.AddExpirationToken(CatalogCacheRegion.CreateChangeToken());
                cacheEntry.AddExpirationToken(_apiChangesWatcher.CreateChangeToken());

                criteria           = criteria.Clone() as CategorySearchCriteria;
                var searchCriteria = criteria.ToCategorySearchCriteriaDto(workContext);
                return(await _searchApi.SearchCategoriesAsync(searchCriteria));
            });

            var result = new PagedList <Category>(new List <Category>().AsQueryable(), 1, 1);

            if (searchResult.Items != null)
            {
                result = new PagedList <Category>(searchResult.Items.Select(x => x.ToCategory(workContext.CurrentLanguage, workContext.CurrentStore)).AsQueryable(), criteria.PageNumber, criteria.PageSize);
            }
            //Set  lazy loading for child categories
            EstablishLazyDependenciesForCategories(result.ToArray());
            return(result);
        }
Exemple #27
0
 protected virtual void ClearCache(IEnumerable <Category> categories)
 {
     CatalogCacheRegion.ExpireRegion();
     SeoInfoCacheRegion.ExpireRegion();
 }