3

I've created a plugin for updating sellable items based on data from an external system. One of the things I need to handle is the case where a SellableItem is moved from Category x to Category y in Commerce. In order to achieve this I need to be able to fetch all "CategoryToSellableItem" relationships in which the SellableItem is referenced.

Unfortunately the only reference to the parent categories on a SellableItem appears to be a pipe SellableItem.ParentCategoryList property.

Any ideas?

3 Answers 3

3

As written before, there is a IDeleteRelationshipPipeline to remove the relation, but you are most probably struggling with getting the Category ids, that the SellableItem relates to, to remove the relations. The relation is stored in ParentCategoryList of the SellableItems, but this list contains Sitecore item ids, and not the Commerce entity ids. So you have to find a Commerce entity ids for each of the categories. I do it like this:

public async Task UpsertSellableItemCategories(ProductModel product, CommercePipelineExecutionContext context)
     {
            var entity = await _findEntityPipeline.Run(new FindEntityArgument(typeof(SellableItem), $"{CommerceEntity.IdPrefix<SellableItem>()}{product.Id}"), context);
            if (entity == null)
            {
                return;
            }

        if (!(entity is SellableItem))
        {
            return;
        }

        var existingSellableItem = entity as SellableItem;
        var categoryIds = existingSellableItem?.ParentCategoryList?.Split('|');

        //Get all existing categories
        var categoryList = await _getManagedListPipeline.Run(new FindEntitiesInListArgument(typeof(Category), CommerceEntity.ListName<Category>(), 0, int.MaxValue), context);
        var lst = categoryList.List.Items.Cast<Category>();

        if (categoryIds != null)
        {
            //For each already related category
            foreach (var categoryId in categoryIds)
            {
                Category category = null;
                foreach (var cat in lst)
                {
                    if (cat.SitecoreId == categoryId)
                    {
                        category = cat;
                        break;
                    }
                }

                if (category != null)
                {
                    //If category should not be related
                    if (!product.Categories.ContainsKey(category.FriendlyId))
                    {
                        //remove relationship
                        await this._deleteRelationshipPipeline.Run(
                            new RelationshipArgument(
                                category.Id,
                                $"{CommerceEntity.IdPrefix<SellableItem>()}{product.Id}",
                                ProductConstants.RelationDefinitions.CategoryToSellableItem
                             )
                            {
                                Mode = new RelationshipMode?(RelationshipMode.Delete)
                            }, context);
                    }
                    else //If category should still be related
                    {
                        //relationship exits, don't add again
                        product.Categories.Remove(category.FriendlyId);
                    }
                }
            }
        }

        foreach (var cat in lst)
        {
            if (product.Categories.ContainsKey(cat.FriendlyId)) //contains only new categories
            {
                await this._createRelationshipPipeline.Run(
                    new RelationshipArgument(
                        cat.Id,
                        $"{CommerceEntity.IdPrefix<SellableItem>()}{product.Id}",
                        ProductConstants.RelationDefinitions.CategoryToSellableItem
                        )
                    {
                        Mode = new RelationshipMode?(RelationshipMode.Create)
                    }, context);
            }
        }
    }
  1. I have a list of the new categories in my ProductModel.Categories, that the SellableItem relates to.
  2. First I remove relation to the ones that are not in the list III
  3. I add the new relations
1
  • This example uses the wrong pipeline to find all the categories you should use findEntitiesInListPipeline , it doesn't even compile. Use this instead //Get all existing categories var categoryList = await _findEntitiesInListPipeline.Run(new FindEntitiesInListArgument(typeof(Category), CommerceEntity.ListName<Category>(), 0, int.MaxValue), context); var lst = categoryList?.List?.Items?.Cast<Category>().ToList() ?? new List<Category>();
    – eloycm
    Commented Nov 12, 2021 at 21:15
1

You need to use next code:

var relation = await _deleteRelationshipPipeline.Run(
                                      new RelationshipArgument("Entity-Category-catalogname-categoryname", "Entity-SellableItem-ID", "CategoryToSellableItem")
                                      {
                                          Mode = new RelationshipMode?(RelationshipMode.Create)
                                      }, context);

you need to replace "catalogname-categoryname" and "Entity-SellableItem-ID" with the right names.

First you need to declare your deleteRelationshipPipeline on your class and to inject into your constructor.

private readonly DeleteRelationshipPipeline _deleteRelationshipPipeline;

public ImportMinionBlock(ICreateSellableItemPipeline createSellableItemPipeline,
            IPersistEntityPipeline persistEntityPipeline,
            ICreateRelationshipPipeline createRelationshipPipeline, IFindEntityPipeline findEntityPipeline,
            EditSellableItemPipeline editSellableItemPipeline, CreateSellableItemVariationPipeline createSellableItemVariationPipeline, DeleteRelationshipPipeline deleteRelationshipPipeline)
        {

            _createSellableItemPipeline = createSellableItemPipeline;
            _persistEntityPipeline = persistEntityPipeline;
            _createRelationshipPipeline = createRelationshipPipeline;
            _findEntityPipeline = findEntityPipeline;
            _editSellableItemPipeline = editSellableItemPipeline;
            _createSellableItemVariationPipeline = createSellableItemVariationPipeline;
            _deleteRelationshipPipeline = deleteRelationshipPipeline;
        }
0

Have a look at 'Sitecore.Commerce.Plugin.Catalog.FindEntityListReferencesBlock'; This will find all relationship definitions for you. I think this is actually used to build the ParentCategoryList property of the SellableItem.

There is a method in there called 'GetRelationshipDefinitions', which gives you all item names. I bet if you tweak it a bit, you can get it to return the entity identifiers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.