Dev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Packages and bundles (dev)

Describes how to work with bundles and packages with relation to the Optimizely Commerce Connect content model.

For an introduction to these concepts, see Packages and bundles in the user documentation.

  • The EPiServer.Commerce.Catalog.Linking.BundleEntry class represents bundle entries.
  • The EPiServer.Commerce.Catalog.Linking.PackageEntry class represents package entries.
  • The EPiServer.Commerce.Catalog.Linking.IRelationRepository service administers each.

The Child property of the BundleEntry or PackageEntry contains the ContentReference of the entry included in the bundle/package. The class also has a SortOrder property for ordering the entries, a GroupName property for grouping entries, and a Quantity property containing the quantity of the entry in the bundle/package.

EPiServer.Commerce.Catalog.Linking.EntryRelation contains the following default values: DefaultGroupName and DefaultQuantity.

A BundleEntry or PackageEntry is uniquely defined by the ContentReference in its Child property together with its Parent property (referencing the bundle or package itself). That is, you cannot add the same entry more than once to the same bundle or package.

Get the entries of a bundle or package

To get bundle or package entries, call the GetChildren method of IRelationRepository with the ContentReference of a bundle or package.

// Retrieve entries from a bundle
public IEnumerable<BundleEntry> ListBundleEntries(ContentReference referenceToBundle)
{
  var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();

  // Relations to bundle entries are of type BundleEntry
  var bundleEntries = relationRepository.GetChildren<BundleEntry>(referenceToBundle);
  return bundleEntries;
}

// Retrieve entries from a package
public IEnumerable<PackageEntry> ListPackageEntries(ContentReference referenceToPackage)
{
  var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();

  // Relations to package entries are of type PackageEntry
  var packageEntries = relationRepository.GetChildren<PackageEntry>(referenceToPackage);
  return packageEntries;
}

Or, you can get the bundle/package entry links from bundle/package content via bundle or package content extensions:

public IEnumerable<ContentReference> ListBundleEntries(BundleContent bundleContent)
{
  var bundleEntryLinks = bundleContent.GetEntries();
  return bundleEntryLinks;
}
    
public IEnumerable<ContentReference> ListPackageEntries(PackageContent packageContent)
{
  var packageEntryLinks = packageContent.GetEntries();
  return packageEntryLinks;
}

Get the bundle or package by an entry

To get the packages or bundles, call the GetParents method of IRelationRepository with the ContentReference of a catalog entry.

public IEnumerable<BundleEntry> GetBundleByEntry(ContentReference entry)
{
  var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();
    
  // Relations between bundle and bundle entry is BundleEntry
  var bundleRelations = relationRepository.GetParents<BundleEntry>(entry);

  return bundleRelations;
}
    
public IEnumerable<PackageEntry> GetPackageByEntry(ContentReference entry)
{
  var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();
    
  // Relations between package and package entry is PackageEntry
  var packageRelations = relationRepository.GetParents<PackageEntry>(entry);
   
  return packageRelations;
}

Or, you can get the bundle or package links from a child item via entry content extensions:

public IEnumerable<ContentReference> GetParentBundles(EntryContentBase entryContent)
{
  var bundleLinks = entryContent.GetParentBundles();
  return bundleLinks;
}
    
public IEnumerable<ContentReference> GetParentPackages(EntryContentBase entryContent)
{
  var packageLinks = entryContent.GetParentPackages();
  return packageLinks;
}

To add BundleEntry or PackageEntry objects to a bundle or package, use the UpdateRelations method or UpdateRelation extension method of IRelationRepository. The new entry must have a Child ContentReference, a Parent ContentReference, and you probably want to specify a Quantity and Group.

public void AddBundleEntry(ContentReference referenceToBundle, ContentReference referenceToProductOrVariation)
{
    var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();

    var newBundleEntry = new BundleEntry
    {
        GroupName = "GroupX",
        Quantity = 1.0m,
        SortOrder = 100,
        Parent = referenceToBundle,
        Child = referenceToProductOrVariation
    };

    relationRepository.UpdateRelation(newBundleEntry);
}

public void AddPackageEntry(ContentReference referenceToPackage, ContentReference referenceToPackageOrVariation)
{
    var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();

    var newPackageEntry = new PackageEntry
    {
        GroupName = "GroupX",
        Quantity = 1.0m,
        SortOrder = 100,
        Parent = referenceToPackage,
        Child = referenceToPackageOrVariation
    };

    relationRepository.UpdateRelation(newPackageEntry);
}

Update an entry in a bundle or package

To update BundleEntry or PackageEntry objects, such as updating the Quantity, use the UpdateRelations method or the UpdateRelation extension method of IRelationRepository. You can construct a new object to replace the old one (matched by the Parent and Child properties). Or, use GetParents to get the existing Relations, filter out the object you want to update, and pass it to UpdateRelation after changing the value.

public void UpdateBundleEntry(ContentReference referenceToBundle, ContentReference referenceToProductOrVariation, decimal newQuantity)
{
    var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();
    var bundleEntries = relationRepository.GetChildren<BundleEntry>(referenceToBundle);

    // Find the matching BundleEntry by comparing the child, ignoring versions since relations are not version specific
    var matchingEntry = bundleEntries.FirstOrDefault(r => r.Child.CompareToIgnoreWorkID(referenceToProductOrVariation));

    // Update if there was a matching entry
    if (matchingEntry != null)
    {
        // Set new data
        matchingEntry.Quantity = newQuantity;

        relationRepository.UpdateRelation(matchingEntry);
    }
}

public void UpdatePackageEntry(ContentReference referenceToPackage, ContentReference referenceToPackageOrVariation, decimal newQuantity)
{
    var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();
    var packageEntries = relationRepository.GetChildren<PackageEntry>(referenceToPackage);

    // Find the matching PackageEntry by comparing the child, ignoring versions since relations are not version specific
    var matchingEntry = packageEntries.FirstOrDefault(r => r.Child.CompareToIgnoreWorkID(referenceToPackageOrVariation));

    // Update if there was a matching entry
    if (matchingEntry != null)
    {
        // Set new data
        matchingEntry.Quantity = newQuantity;

        relationRepository.UpdateRelation(matchingEntry);
    }
}

Remove an entry from a bundle or package

To remove an entry from a bundle or package, call the RemoveRelations method or RemoveRelation extension method of IRelationRepository with a BundleEntry or PackageEntry object matching an existing bundle or package entry. You can construct a matching object, or use GetParents to get the existing Relations, to filter out the object you want to remove and pass it to RemoveRelation.

public void RemoveBundleEntry(ContentReference referenceToBundle, ContentReference referenceToProductOrVariation)
{
    var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();

    // Define a relation matching the one to remove, or use
    // GetRelations to find the one you want to remove and pass that to
    // RemoveRelation
    var relationToRemove = new BundleEntry
    {
        Parent = referenceToBundle,
        Child = referenceToProductOrVariation
    };

    // Removes matching BundleEntry, or no action if no match exists
    relationRepository.RemoveRelation(relationToRemove);
}

public void RemovePackageEntry(ContentReference referenceToPackage, ContentReference referenceToPackageOrVariation)
{
    var relationRepository = ServiceLocator.Current.GetInstance<IRelationRepository>();

    // Define a relation matching the one to remove, or use
    // GetRelations to find the one you want to remove and pass that to
    // RemoveRelation
    var relationToRemove = new PackageEntry
    {
        Parent = referenceToPackage,
        Child = referenceToPackageOrVariation
    };

    // Removes matching PackageEntry, or no action if no match exists
    relationRepository.RemoveRelation(relationToRemove);
}