DEV Community

tackme
tackme

Posted on • Edited on

Update all items that share the same catalog entity when the item is saved

In Sitecore Commerce, a category/product entity associated with the different parents is treated as the different items in the Content Editor. Each item's fields are kept in the entity's ExternalSettings component per entity relationship. So one item is edited, the others will not be updated. You can change this behavior by customizing the CatalogDataProvider class.

To retrieve all items that share an entity, use the CatalogRepository class. The implementation is the following.

public List<Item> GetEntityShareCatalogItems(Item item)
{
    // Deterministic ID is an item's ID in the Content Editor.
    var deterministicId = item.ID.Guid.ToString();

    // Sitecore ID is an one-to-one GUID with the entity.
    // This is used for mapping entity with items internally, so not visible in the Content Editor.
    var catalogRepository = new CatalogRepository(item.Language.Name);
    var sitecoreId = catalogRepository.GetSitecoreIdForDeterministicId(deterministicId);
    if (string.IsNullOrWhiteSpace(sitecoreId))
    {
        return new List<Item> { item };
    }

    var entityId = catalogRepository.GetEntityIdFromMappings(sitecoreId);
    if (string.IsNullOrWhiteSpace(entityId))
    {
        return new List<Item> { item };
    }

    // Get all items that share the entity ID.
    var deterministicIds = catalogRepository.GetDeterministicIdsForEntityId(entityId, includeVariations: true);
    if (deterministicIds == null || !deterministicIds.Any())
    {
        return new List<Item> { item };
    }

    return deterministicIds
        .Select(id => ID.Parse(id, ID.Null))
        .Select(item.Database.GetItem)
        .Where(item => item?.Name == item.Name)
        .Where(item => item.DescendsFrom(item.TemplateID))
        .Where(item => item.Language == item.Language)
        .ToList();
}
Enter fullscreen mode Exit fullscreen mode

And apply field changes to all the items by customizing the CatalogDataProvider.SaveItem method.

public class MyCatalogDataProvider : CatalogDataProvider
{
    public override bool SaveItem(ItemDefinition itemDefinition, ItemChanges changes, CallContext context)
    {
        if (!CanProcessItem(itemDefinition, false))
        {
            return false;
        }

        using (new LanguageSwitcher(changes.Item.Language))
        {
            // Call the method here.
            var catalogItems = GetEntityShareCatalogItems(changes.Item);
            var success = true;

            // Apply the same changes to all the items.
            foreach (var item in catalogItems)
            {
                var definition = new ItemDefinition(item.ID, itemDefinition.Name, itemDefinition.TemplateID, itemDefinition.BranchId);
                var clonedChanges = changes.Clone(item);

                try
                {
                    success &= base.SaveItem(definition, clonedChanges, context);
                }
                catch (Exception ex)
                {
                    success = false;
                }
            }

            return success;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Then replace the default data provider with the customized one.

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <dataProviders>
      <catalogProvider type="Sitecore.Commerce.Engine.Connect.DataProvider.CatalogDataProvider, Sitecore.Commerce.Engine.Connect">
        <patch:attribute name="type">Namespace.To.MyCatalogDataProvider, Assembly</patch:attribute>
      </catalogProvider>
    </dataProviders>
  </sitecore>
</configuration>
Enter fullscreen mode Exit fullscreen mode

Now when a catalog item is saved, all related items are updated together.

Top comments (0)