There are two big types of relations in Episerver (Optimizely) B2C Commerce: relations between entries and nodes, and between nodes. As you will most likely have to touch one or another, or both, sooner or later, this post aims to give you some understanding on how they are structured/work.
When you add a product (or variant, or package, or bundle) to a category, you are creating a
NodeEntryRelation. And there are a two types of
NodeEntryRelation, which means the category is counted as true parent of the entry. Each entry can only have at most one primary
NodeEntryRelation(Which means it can have no primary
NodeEntryRelation, which means the entry is linked to the category. You do that when it makes sense for the product to be in additional categories. for example, a GoPro can be in Camera (primary category), but can also be in Sport Gears (linked). An entry can have no, or multiple secondary
The concept of primary
NodeEntryRelation was added to Commerce 11. Before that, it’s a bit more of a guess work – the “main” category is determined by the sort order – the relation with lowest sort order is considered “main relation”. That introduces some inconsistency, which prompted the rework on that.
What is the main different between those two things? For one thing, access rights. For Commerce, you can set access rights down to categories, but not entries. The entries will inherit access rights from their true parents (i.e. primary nodes). An entry without primary node-entry relation is considered the direct children of a catalog, and inherits its access right settings.
Another smaller difference is that if you delete a category, true children entries will be deleted. Linked entries will only be detached from that category.
NodeEntryRelation can be managed fully by
IRelationRepository, using the
NodeEntryRelation type, and you can use a few extension methods to make it easier – for example
How are your actions in Catalog UI reflected on a data level:
- When you create a new entry (product/SKU/etc.) in a category, you create a primary node-entry relation for them
- When you move (cut then paste) an entry to a new category, you are creating a new primary node-entry relation. If the entry already has a primary node-entry relation, the new one will take over.
- When you link/detach an entry to/from a new category, you are creating/removing a non-primary node-entry relation
Like Node-Entry relation, a node can be a true parent of a node, or just be a “linked” parent.
Unlike Node-Entry relation, Node-Node relation is quite different that it’s separated in two places.
- Linked nodes are represented by
NodeRelation(s)(it might be interesting to know that
NodeRelationis the parent class of
NodeEntryRelation. The interpretation is that a
NodeRelationis – a relation of a node, which can be with another node, or an entry)
- There is no primary
NodeRelation, the true parent node is identified by a property of the category itself. When you have a
NodeContentcontent, then the
ParentLinkproperty points to the true parent.
For that reason, a node will always have a true parent, either a catalog, or a node. You can’t use
IRelationRepository (and therefore, ServiceAPI) to manage (delete or update) a true parent of a node , you would have to:
- Set its
ParentLinkto something else
IContentRepository.Moveto move it to a new parent.
Note that this is the limitation of the Relations API in ServiceAPI. You can technically change the
ParentLinkof a node and update via POST. It’s just more work and not as intuitive as the Relations API.
Why the disparity, you might ask? Well, a lot of design decisions in Commerce comes from historical reasons, and after that, constrained resources (time/man power) and priority. While the disparity is probably not the best thing you want, it still works fairly well, and if you understand the quirk then it is all well.