public async Task DoImportAsync(Stream inputStream, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var progressInfo = new ExportImportProgressInfo(); using (var streamReader = new StreamReader(inputStream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { if (reader.Value.ToString() == "Sitemaps") { await reader.DeserializeJsonArrayWithPagingAsync <Sitemap>(_jsonSerializer, _batchSize, items => _sitemapService.SaveChangesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } site maps have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "SitemapItems") { await reader.DeserializeJsonArrayWithPagingAsync <SitemapItem>(_jsonSerializer, _batchSize, items => _sitemapItemService.SaveChangesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } site maps items have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } } }
public async Task DoImportAsync(Stream inputStream, ExportImportOptions options, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var progressInfo = new ExportImportProgressInfo(); using (var streamReader = new StreamReader(inputStream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { if (reader.Value.ToString() == "MenuLinkLists") { await reader.DeserializeJsonArrayWithPagingAsync <MenuLinkList>(_jsonSerializer, _batchSize, async items => { foreach (var item in items) { await _menuService.AddOrUpdateAsync(item); } }, processedCount => { progressInfo.Description = $"{ processedCount } menu links have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "CmsContent") { if (options != null && options.HandleBinaryData) { progressInfo.Description = "importing binary data: themes and pages importing..."; progressCallback(progressInfo); await reader.DeserializeJsonArrayWithPagingAsync <ContentFolder>(_jsonSerializer, _batchSize, items => { foreach (var item in items) { SaveContentFolderRecursive(item, progressCallback); } return(Task.CompletedTask); }, processedCount => { progressInfo.Description = $"{ processedCount } menu links have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } } } }
public async Task DoImportAsync(Stream inputStream, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var progressInfo = new ExportImportProgressInfo(); progressInfo.Description = "Importing dynamic associations…"; progressCallback(progressInfo); using (var streamReader = new StreamReader(inputStream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType != JsonToken.PropertyName) { continue; } if (reader.Value.ToString() == "DynamicAssociations") { await reader.DeserializeJsonArrayWithPagingAsync <Association>(_serializer, _batchSize, async items => { await _associationService.SaveChangesAsync(items.ToArray()); }, processedCount => { progressInfo.Description = $"{processedCount} Tagged items have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } }
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); }
private async Task ImportDynamicPropertyDictionaryItemsInternalAsync(JsonTextReader reader, JsonSerializer jsonSerializer, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { await reader.DeserializeJsonArrayWithPagingAsync <DynamicPropertyDictionaryItem>(jsonSerializer, _batchSize, items => _dynamicPropertyDictionaryItemsService.SaveDictionaryItemsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } coupons have been imported"; progressCallback(progressInfo); }, cancellationToken); }
private async Task ImportUserApiKeysInternalAsync(JsonTextReader reader, JsonSerializer jsonSerializer, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { await reader.DeserializeJsonArrayWithPagingAsync <UserApiKey>(jsonSerializer, _batchSize, items => _userApiKeyService.SaveApiKeysAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } api keys have been imported"; progressCallback(progressInfo); }, cancellationToken); }
public async Task DoImportAsync(Stream stream, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var progressInfo = new ExportImportProgressInfo(); using (var streamReader = new StreamReader(stream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { var readerValue = reader.Value.ToString(); if (readerValue == "Pricelists") { await reader.DeserializeJsonArrayWithPagingAsync <Pricelist>(_jsonSerializer, BatchSize, items => _pricingService.SavePricelistsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } price lists have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (readerValue == "Prices") { await reader.DeserializeJsonArrayWithPagingAsync <Price>(_jsonSerializer, BatchSize, items => _pricingService.SavePricesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"Prices: {progressInfo.ProcessedCount} have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (readerValue == "Assignments") { await reader.DeserializeJsonArrayWithPagingAsync <PricelistAssignment>(_jsonSerializer, BatchSize, items => _pricingService.SavePricelistAssignmentsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{progressInfo.ProcessedCount} assignments have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } } }
private async Task ImportCatalogsAsync(JsonTextReader reader, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { await reader.DeserializeJsonArrayWithPagingAsync <Catalog>(_jsonSerializer, _batchSize, async (items) => { await _catalogService.SaveChangesAsync(items.ToArray()); }, processedCount => { progressInfo.Description = $"{ processedCount } catalogs have been imported"; progressCallback(progressInfo); }, cancellationToken); }
private async Task ImportProductsAsync(JsonTextReader reader, ExportImportOptions options, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { var associationBackupMap = new Dictionary <string, IList <ProductAssociation> >(); await reader.DeserializeJsonArrayWithPagingAsync <CatalogProduct>(_jsonSerializer, _batchSize, async (items) => { var products = items.Select(product => { //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; return(product); }).ToArray(); await _itemService.SaveChangesAsync(products.ToArray()); if (options != null && options.HandleBinaryData) { ImportImages(products.OfType <IHasImages>().ToArray(), progressInfo); } }, 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); } }
private async Task ImportCategoriesAsync(JsonTextReader reader, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { 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); }
private async Task ImportSettingsInternalAsync(JsonTextReader reader, JsonSerializer jsonSerializer, PlatformExportManifest manifest, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { await reader.DeserializeJsonArrayWithPagingAsync <ObjectSettingEntry>(jsonSerializer, int.MaxValue, async items => { var arrayItems = items.ToArray(); foreach (var module in manifest.Modules) { await _settingsManager.SaveObjectSettingsAsync(arrayItems.Where(x => x.ModuleId == module.Id).ToArray()); } }, processedCount => { progressInfo.Description = $"{ processedCount } coupons have been imported"; progressCallback(progressInfo); }, cancellationToken); }
private async Task ImportPropertiesAsync(JsonTextReader reader, List <Property> propertiesWithForeignKeys, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { 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); }
private async Task ImportUsersInternalAsync(JsonTextReader reader, JsonSerializer jsonSerializer, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { await reader.DeserializeJsonArrayWithPagingAsync <ApplicationUser>(jsonSerializer, _batchSize, async items => { foreach (var user in items) { var userExists = !(string.IsNullOrEmpty(user.Id) || await _userManager.FindByIdAsync(user.Id) is null) || (await _userManager.FindByNameAsync(user.UserName)) != null; var result = userExists ? await _userManager.UpdateAsync(user) : await _userManager.CreateAsync(user); if (!result.Succeeded) { progressInfo.Errors.AddRange(result.Errors.Select(x => x.Description)); } } }, processedCount => { progressInfo.Description = $"{ processedCount } roles have been imported"; progressCallback(progressInfo); }, cancellationToken); }
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, items => _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); //if (options.HandleBinaryData) { 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) => { foreach (var property in items) { 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(items.ToArray()); }, 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") { await reader.DeserializeJsonArrayWithPagingAsync <CatalogProduct>(_jsonSerializer, _batchSize, async (items) => { var itemsArray = items.ToArray(); await _itemService.SaveChangesAsync(itemsArray); //if (options.HandleBinaryData) { ImportImages(itemsArray.OfType <IHasImages>().ToArray(), progressInfo); } }, processedCount => { progressInfo.Description = $"{ processedCount } products have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } } //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 ImportPlatformEntriesInternalAsync(ZipArchive zipArchive, PlatformExportManifest manifest, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { var progressInfo = new ExportImportProgressInfo(); var jsonSerializer = GetJsonSerializer(); var batchSize = 20; var platformZipEntries = zipArchive.GetEntry(PlatformZipEntryName); if (platformZipEntries != null) { using (var stream = platformZipEntries.Open()) { using (var streamReader = new StreamReader(stream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { if (manifest.HandleSecurity && reader.Value.ToString().EqualsInvariant("Roles")) { await reader.DeserializeJsonArrayWithPagingAsync <Role>(jsonSerializer, batchSize, async items => { foreach (var role in items) { if (await _roleManager.RoleExistsAsync(role.Name)) { await _roleManager.UpdateAsync(role); } else { await _roleManager.CreateAsync(role); } } }, processedCount => { progressInfo.Description = $"{ processedCount } roles have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (manifest.HandleSecurity && reader.Value.ToString().EqualsInvariant("Users")) { await reader.DeserializeJsonArrayWithPagingAsync <ApplicationUser>(jsonSerializer, batchSize, async items => { foreach (var user in items) { var userExist = await _userManager.FindByIdAsync(user.Id); if (userExist != null) { await _userManager.UpdateAsync(user); } else { await _userManager.CreateAsync(user); } } }, processedCount => { progressInfo.Description = $"{ processedCount } roles have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (manifest.HandleSettings && reader.Value.ToString() == "Settings") { await reader.DeserializeJsonArrayWithPagingAsync <ObjectSettingEntry>(jsonSerializer, int.MaxValue, async items => { var arrayItems = items.ToArray(); foreach (var module in manifest.Modules) { await _settingsManager.SaveObjectSettingsAsync(arrayItems.Where(x => x.ModuleId == module.Id).ToArray()); } }, processedCount => { progressInfo.Description = $"{ processedCount } coupons have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (manifest.HandleSettings && reader.Value.ToString() == "DynamicProperties") { await reader.DeserializeJsonArrayWithPagingAsync <DynamicProperty>(jsonSerializer, batchSize, items => _dynamicPropertyService.SaveDynamicPropertiesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } coupons have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (manifest.HandleSettings && reader.Value.ToString() == "DynamicPropertyDictionaryItems") { await reader.DeserializeJsonArrayWithPagingAsync <DynamicPropertyDictionaryItem>(jsonSerializer, batchSize, items => _dynamicPropertyService.SaveDictionaryItemsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } coupons have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } } } } }
public async Task DoImportAsync(Stream inputStream, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var progressInfo = new ExportImportProgressInfo(); using (var streamReader = new StreamReader(inputStream)) using (var reader = new JsonTextReader(streamReader)) { while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { if (reader.Value.ToString() == "Promotions") { await reader.DeserializeJsonArrayWithPagingAsync <Promotion>(_jsonSerializer, _batchSize, items => _promotionService.SavePromotionsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } promotions have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "DynamicContentFolders") { await reader.DeserializeJsonArrayWithPagingAsync <DynamicContentFolder>(_jsonSerializer, _batchSize, items => _dynamicContentService.SaveFoldersAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } dynamic content items have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "DynamicContentItems") { await reader.DeserializeJsonArrayWithPagingAsync <DynamicContentItem>(_jsonSerializer, _batchSize, items => _dynamicContentService.SaveContentItemsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } dynamic content items have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "DynamicContentPlaces") { await reader.DeserializeJsonArrayWithPagingAsync <DynamicContentPlace>(_jsonSerializer, _batchSize, items => _dynamicContentService.SavePlacesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } dynamic content places have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "DynamicContentPublications") { await reader.DeserializeJsonArrayWithPagingAsync <DynamicContentPublication>(_jsonSerializer, _batchSize, items => _dynamicContentService.SavePublicationsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } dynamic content publications have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "Coupons") { await reader.DeserializeJsonArrayWithPagingAsync <Coupon>(_jsonSerializer, _batchSize, items => _couponService.SaveCouponsAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } coupons have been imported"; progressCallback(progressInfo); }, cancellationToken); } else if (reader.Value.ToString() == "Usages") { await reader.DeserializeJsonArrayWithPagingAsync <PromotionUsage>(_jsonSerializer, _batchSize, items => _promotionUsageService.SaveUsagesAsync(items.ToArray()), processedCount => { progressInfo.Description = $"{ processedCount } usages have been imported"; progressCallback(progressInfo); }, cancellationToken); } } } } }
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); } } }