private async Task ResolvePropertyDictionaryItems(List <CsvProduct> csvProducts, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback) { var allDictPropertyIds = csvProducts.SelectMany(x => x.Properties).Where(x => x.Dictionary) .Select(x => x.Id).Distinct() .ToArray(); var allDictItems = (await _propDictItemSearchService.SearchAsync(new PropertyDictionaryItemSearchCriteria { PropertyIds = allDictPropertyIds, Take = int.MaxValue })).Results; foreach (var dictProperty in csvProducts.SelectMany(x => x.Properties).Where(x => x.Dictionary && x.Values?.Any(v => v != null) == true)) { foreach (var propertyValue in dictProperty.Values.Where(x => x.Value != null)) { // VP-5516: // For imported propertyValue the Alias field is empty - need to fill it from value. // For existing propertyValue Alias should be already filled, we shouldn't rewrite it. propertyValue.Alias = string.IsNullOrEmpty(propertyValue.Alias) ? propertyValue.Value.ToString() : propertyValue.Alias; var existentDictItem = allDictItems.FirstOrDefault(x => x.PropertyId == propertyValue.PropertyId && x.Alias.EqualsInvariant(propertyValue.Alias)); if (existentDictItem == null) { if (CreatePropertyDictionatyValues) { existentDictItem = new PropertyDictionaryItem { Alias = propertyValue.Alias, PropertyId = propertyValue.PropertyId }; allDictItems.Add(existentDictItem); await _propDictItemService.SaveChangesAsync(new[] { existentDictItem }); } else { progressInfo.Errors.Add($"The '{propertyValue.Alias}' dictionary item is not found in '{propertyValue.PropertyName}' dictionary"); progressCallback(progressInfo); } } propertyValue.ValueId = existentDictItem?.Id; } } }
public async Task <ActionResult> SaveChanges([FromBody] PropertyDictionaryItem[] propertyDictItems) { await _propertyDictionaryService.SaveChangesAsync(propertyDictItems); return(Ok()); }
public async Task DoImportAsync(Stream inputStream, ExportImportOptions options, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var progressInfo = new ExportImportProgressInfo(); var propertiesWithForeignKeys = new List <Property>(); using (var streamReader = new StreamReader(inputStream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { if (reader.Value.ToString() == "Catalogs") { await reader.DeserializeJsonArrayWithPagingAsync <Catalog>(_jsonSerializer, _batchSize, async (items) => { await _catalogService.SaveChangesAsync(items.ToArray()); }, processedCount => { progressInfo.Description = $"{ processedCount } catalogs have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "Categories") { await reader.DeserializeJsonArrayWithPagingAsync <Category>(_jsonSerializer, _batchSize, async (items) => { var itemsArray = items.ToArray(); await _categoryService.SaveChangesAsync(itemsArray); ImportImages(itemsArray.OfType <IHasImages>().ToArray(), progressInfo); }, processedCount => { progressInfo.Description = $"{ processedCount } categories have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "Properties") { await reader.DeserializeJsonArrayWithPagingAsync <Property>(_jsonSerializer, _batchSize, async (items) => { var itemsArray = items.ToArray(); foreach (var property in itemsArray) { if (property.CategoryId != null || property.CatalogId != null) { propertiesWithForeignKeys.Add(property.Clone() as Property); //Need to reset property foreign keys to prevent FK violation during inserting into database property.CategoryId = null; property.CatalogId = null; } } await _propertyService.SaveChangesAsync(itemsArray); }, processedCount => { progressInfo.Description = $"{ processedCount } properties have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "PropertyDictionaryItems") { await reader.DeserializeJsonArrayWithPagingAsync <PropertyDictionaryItem>(_jsonSerializer, _batchSize, items => _propertyDictionaryService.SaveChangesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } property dictionary items have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "Products") { var associationBackupMap = new Dictionary <string, IList <ProductAssociation> >(); var products = new List <CatalogProduct>(); await reader.DeserializeJsonArrayWithPagingAsync <CatalogProduct>(_jsonSerializer, _batchSize, async (items) => { var itemsArray = items.ToArray(); foreach (var product in itemsArray) { //Do not save associations withing product to prevent dependency conflicts in db //we will save separateley after product import if (!product.Associations.IsNullOrEmpty()) { associationBackupMap[product.Id] = product.Associations; } product.Associations = null; products.Add(product); } await _itemService.SaveChangesAsync(products.ToArray()); if (options != null && options.HandleBinaryData) { ImportImages(itemsArray.OfType <IHasImages>().ToArray(), progressInfo); } products.Clear(); }, processedCount => { progressInfo.Description = $"{ processedCount } products have been imported"; progressCallback(progressInfo); }, cancellationToken); //Import products associations separately to avoid DB constrain violation var totalProductsWithAssociationsCount = associationBackupMap.Count; for (var i = 0; i < totalProductsWithAssociationsCount; i += _batchSize) { var fakeProducts = new List <CatalogProduct>(); foreach (var pair in associationBackupMap.Skip(i).Take(_batchSize)) { var fakeProduct = AbstractTypeFactory <CatalogProduct> .TryCreateInstance(); fakeProduct.Id = pair.Key; fakeProduct.Associations = pair.Value; fakeProducts.Add(fakeProduct); } await _associationService.SaveChangesAsync(fakeProducts.OfType <IHasAssociations>().ToArray()); progressInfo.Description = $"{ Math.Min(totalProductsWithAssociationsCount, i + _batchSize) } of { totalProductsWithAssociationsCount } products associations imported"; progressCallback(progressInfo); } } } } } //Update property associations after all required data are saved (Catalogs and Categories) if (propertiesWithForeignKeys.Count > 0) { progressInfo.Description = $"Updating {propertiesWithForeignKeys.Count} property associations…"; progressCallback(progressInfo); var totalCount = propertiesWithForeignKeys.Count; for (var i = 0; i < totalCount; i += _batchSize) { await _propertyService.SaveChangesAsync(propertiesWithForeignKeys.Skip(i).Take(_batchSize).ToArray()); progressInfo.Description = $"{ Math.Min(totalCount, i + _batchSize) } of { totalCount } property associations updated."; progressCallback(progressInfo); } } }
private async Task ImportPropertyDictionaryItemsAsync(JsonTextReader reader, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { await reader.DeserializeJsonArrayWithPagingAsync <PropertyDictionaryItem>(_jsonSerializer, _batchSize, items => _propertyDictionaryService.SaveChangesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } property dictionary items have been imported"; progressCallback(progressInfo); }, cancellationToken); }