Example of saving batch of products to DB using ICatalogSystem


I am trying to wrap my head around creating a list of products that should be persisted to DB in a batch. The list will easily consist of thousands of products. 

I was looking into possibility to use ICatalogSystem and CatalogEntryDto's data table and ran into so many questions on handling relations and multi language content. There is no clear example on the blogs, so I was wondering if there is someone who has experience on this matter?

Any insight is more than welcome.

Jan 29, 2020 15:15

Hi Quan and thanks for insight. There is no way for us to upgrade to that version in next couple of months. Many integrations prohibit that at the moment. I was kinda hopping to solve it (for now) with help of ICatalogSystem based on one of your earlier answers on some thread. You've explained that basically CatalogEntryDto is a data table and could hold many rows before persising it to the data base.

Feb 13, 2020 8:13

CatalogEntryDto only holds basic information, you still need to save the MetaObject(s). It can be quite complicated 

Feb 13, 2020 9:09


I want to save products, items and categories to the epi commerce database by using the CatalogEntryDto. Could you please ellaborate on the saving of MetaObject? That would be much appreciated!

Thanks in advance.

Mar 11, 2021 14:55

actually I am able to save product and item to datbase using this:

            // Save the metadata attributes associated with the catalog entry.
            var metaContext = new MetaDataContext();
            var metaClass = MetaClass.Load(metaContext, newEntryRow.MetaClassId);
            var metaObj = new MetaObject(metaClass);
            MetaHelper.SetMetaFieldValue(metaContext, metaObj, "Title", new object[] { "New Book Title" });
            MetaHelper.SetMetaFieldValue(metaContext, metaObj, "ID", new object[] { "New Id" });
            MetaHelper.SetMetaFieldValue(metaContext, metaObj, "Description", new object[] { "New Description" });
            MetaHelper.SetMetaFieldValue(metaContext, metaObj, "Theme", new object[] { "New Book Title" });
            MetaHelper.SetMetaFieldValue(metaContext, metaObj, "Highlight", new object[] { false });

but the product is not showing up in the catalog tree in commerce GUI.

Mar 11, 2021 15:09

MetaObject is the "lower layer" of the content properties, so you will need to load the metaobject corresponding to the entry, update it fields and then save it back. I would strongly recommend to use the content APi for the purpose (or the batch API if you need performance)

Mar 11, 2021 15:10

Agree with Quan - I have written an import function a long time ago using CatalogEntryDto and I had a lot of performance issues (It was a one-off import so I survived )

But as Goran mentioned if you can not use batch API then I can share code snippet.

public void ImportProductsNew(MigrationConfig migrationConfig)
			var catalogDal = new MM_CatalogEntryDAL();

			while (catalogDal.GetAllProductsToImport(1).Count > 0)
				var products = catalogDal.GetAllProductsToImport(migrationConfig.BatchSetting.ImportProductBatch).ToList();
				MetaDataContext metaContext = CatalogContext.MetaDataContext;
				IContentRepository contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
				IContentTypeRepository contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
				var referenceConverter = ServiceLocator.Current.GetInstance<ReferenceConverter>();
				var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
				var commerceRootContent = contentLoader.GetChildren<CatalogContent>(referenceConverter.GetRootLink()).First();

				foreach (var product in products)
						ContentType correctType = contentTypeRepository.Load(product.ProductType.ProductTypeName);

						var productCode = product.ProductCode;
						var productName = product.ProductName;
						var catalogId = product.CatalogNode.Catalog.EpiserverCatalogId ?? 0;
						var catalogNodeId = product.CatalogNode.EpiserverCatalogNodeId ?? 0;

						CatalogEntryDto entry = CatalogContext.Current.GetCatalogEntryDto(productCode,
						 new CatalogEntryResponseGroup(CatalogEntryResponseGroup.ResponseGroup.CatalogEntryFull));
						if (entry.CatalogEntry.Count == 0)

							MetaClass metaClass = MetaClass.Load(metaContext, product.ProductType.ProductTypeName);

							// Get a new entry row for your catalog entry.
							CatalogEntryDto.CatalogEntryRow newEntryRow = entry.CatalogEntry.NewCatalogEntryRow();

							// Set entry properties.
							newEntryRow.ApplicationId = AppContext.Current.ApplicationId;
							newEntryRow.CatalogId = catalogId;
							newEntryRow.ClassTypeId = "Product";
							newEntryRow.Code = productCode;
							newEntryRow.EndDate = DateTime.Now.AddYears(50).ToUniversalTime();
							newEntryRow.IsActive = true;
							newEntryRow.MetaClassId = metaClass.Id;
							newEntryRow.Name = productName;
							newEntryRow.StartDate = DateTime.UtcNow;
							newEntryRow.TemplateName = "default"; // system-defined template of type 'entry'
																  // newEntryRow.SetSerializedDataNull();
							if (newEntryRow.RowState == DataRowState.Detached)

							// Set SEO properties.
							CatalogEntryDto.CatalogItemSeoRow newSeoRow = entry.CatalogItemSeo.NewCatalogItemSeoRow();
							newSeoRow.ApplicationId = AppContext.Current.ApplicationId;
							newSeoRow.CatalogEntryId = newEntryRow.CatalogEntryId;
							// newSeoRow.CatalogNodeId = catalogNodeId;
							newSeoRow.LanguageCode = "en-GB"; // your language settings

							newSeoRow.Uri = CommerceHelper.CleanUrlField(product.ProductName).ToLower(); 
							newSeoRow.UriSegment = CommerceHelper.CleanUrlField(product.ProductName).ToLower();
							if (newSeoRow.RowState == DataRowState.Detached)


							CatalogRelationDto relation = new CatalogRelationDto();
							// Set the entry node relation.


							product.EpiserverCatalogEntryId = newEntryRow.CatalogEntryId;
							//We use the content link builder to get the contentlink to our product
							var productLink = referenceConverter.GetContentLink(newEntryRow.CatalogEntryId, CatalogContentType.CatalogEntry, 0);
							product.EpiserverUrl = new UrlHelper().ContentUrl(productLink);

							// Save the meta data attributes associated with the catalog entry.
							metaContext.UseCurrentThreadCulture = false;

							metaContext.Language = "en-GB"; // your language settings

							MetaObjectSerialized serialized = new Mediachase.Commerce.Storage.MetaObjectSerialized();
							MetaObject metaObj = new MetaObject(metaClass, entry.CatalogEntry[0].CatalogEntryId);   //    MetaObject.NewObject(metaContext, entry.CatalogEntry[0].CatalogEntryId, metaClass.Id, "admin");

							MetaHelper.SetMetaFieldValue(metaContext, metaObj, "DisplayName", new object[] { product.ProductName });

							if (product.ProductType.ProductTypeName == "your-product")
								MetaHelper.SetMetaFieldValue(metaContext, metaObj, "ProductId", new object[] { "SH_" + RandomNumberHelper.Get8DigitRandomNumber() });

							foreach (var property in product.ProductProperties)

								// update rest of product properties

							MetaHelper.SetMetaFieldValue(metaContext, metaObj, "PrimaryImage", new object[] { GlobalStartPage.PlaceHolderImage.ToString() });
							var imageProperties = product.ProductImages.GroupBy(a => a.DesPropertyName).Select(a => new { a.Key, Count = a.Count(), Images = a.ToList() });
							foreach (var imageProperty in imageProperties)
								// Save images


							serialized.AddMetaObject("en-GB", metaObj);
							newEntryRow.SerializedData = serialized.BinaryValue;
							metaContext.UseCurrentThreadCulture = true;

							product.Status = "Existed";
					catch (Exception ex)
						product.Status = (product.EpiserverCatalogEntryId ?? 0) > 0 ? "Added with error" : "fail";
						product.ErrorDetails += ex.Message;


Mar 11, 2021 15:31
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.