Jeff Valdez
Jun 14, 2012
visibility 5388
star star star star star
(1 votes)

Entry SortOrder Property, Where Are You?

An EPiServer partner developer asked a question today about the entry sort order property. He could find the interface to affect changes on catalog entry sort order values in Commerce Manager, but couldn’t intuitively find the API hooks within the Mediachase.Commerce.dll assembly. I thought this would be a good topic for an initial blog post.

The sort property for a catalog entry is actually manipulated via a different strongly typed dataset object than the CatalogEntryDto, namely the CatalogRelationDto. In this DTO, we use the NodeEntryRelation datatable and find the desired records based on a unique combination of CatalogId, CatalogNodeId, and CatalogEntryId. Once we have a reference to the row we can affect the SortOrder property and then persist changes as needed.

To get this dataset object, you can use one of the three GetCatalogRelationDto() method overloads from the CatalogContext singleton. The easiest one in this case is the one that takes an integer entry id.

In this method, execution is passed to the CatalogRelationManager, then down to the CatalogRelationAdmin where the stored procedure [ecf_CatalogRelationByChildEntryId] is executed. Query results are mapped to three of CatalogRelationDto's datatables: CatalogNodeRelation, CatalogEntryRelation, NodeEntryRelation. At this point you can iterate through the strongly typed (CatalogRelationDto.NodeEntryRelationRow) datarows of the NodeEntryRelation datatable.

Below is a trivial example. (Apologies if the blog theme horizontally truncates the syntax highlighted portion below.)

   1:  // set parameters
   2:  int catalogEntryId = 7;
   3:  int newSortOrderValue = 10;
   4:   
   5:  CatalogRelationDto catalogRelationDto = 
   6:    CatalogContext.Current.GetCatalogRelationDto();
   7:   
   8:  foreach (CatalogRelationDto.NodeEntryRelationRow row 
   9:    in catalogRelationDto.NodeEntryRelation)
  10:  {
  11:    if (row.RowState != DataRowState.Deleted 
  12:      && row.CatalogEntryId == catalogEntryId)
  13:    {
  14:      // set the value of our NodeEntryRelationRow instance
  15:      row.SortOrder = newSortOrderValue;
  16:    }
  17:  }

Finally, to persist those datarow changes you can use the SaveCatalogRelationDto() method from the CatalogContext singleton. The easiest one in this case is the one that takes an integer entry id.

   1:  // persist changes
   2:  if (catalogRelationDto.HasChanges())
   3:  {
   4:    CatalogContext.Current.SaveCatalogRelationDto(catalogRelationDto);
   5:  }

In this method, execution is again passed to the CatalogRelationManager which raises some pre and post processing pipeline events around the save operation and clears old cached records. The save operation is handled by a CatalogRelationAdmin instance where the DataHelper class is used to persist the dataset.

When looking at the catalog API, you’ll come across this pattern frequently. There is a singleton class funneling calls through a single instance of ICatalogSystem which contains the underlying concrete definition based on configuration. From there methods usually go through a manager class where other framework tasks can be injected, such as caching objects and raising events. Finally, the baton is passed to an admin class where the intended work is done. You may also run head first into the Mediachase.MetaDataPlus.dll assembly, but that is a blog post for another day. Along the way there are strongly typed datasets for ease of programming that seemingly map directly against the database schema and database objects, as well as C# POCO objects to abstract away the details.

We should see these libraries, and the layers that allow presentation, integration, and other functions above improve and innovate in future versions, can’t wait!

Jun 14, 2012

Comments

Jun 15, 2012 02:33 PM

Welcome Jeff and what a great way to start your EPiServer World blogging career!

error Please login to comment.
Latest blogs
Finding Thomas Part 3 - The Moment of Recognition

Remember Thomas? In digital landscape, Thomas is the returning visitor who reads everything, opens every email, converts on nothing. In standard...

Ritu Madan | Jun 26, 2026

Add more scheduled job settings from the Optimizely CMS 12 admin UI -- with OptiScheduledJob.ExtraParameters

  Optimizely (EPiServer) CMS 12 ships a great scheduled-jobs framework, but it has one frustrating gap: a job has nowhere to store its own...

Binh Nguyen Thi | Jun 25, 2026

Automated Search & Navigation to Graph Migration with Claude Code

A Claude Code plugin that scans your S&N codebase, applies Graph SDK transformations, and validates the result. Install once, run one command. CMS ...

Connor Fortin | Jun 24, 2026

Migrating from Find to Graph: Lessons Learned from a Real CMS 13 Project

While migrating a search solution from Optimizely Search & Navigation (Find) to Optimizely Graph in CMS 13, I encountered several issues that were...

Binh Nguyen Thi | Jun 24, 2026

Optimizely: Upgrade Opti-ID and .NET 10 in CMS 12

Many Optimizely customers are planning their roadmap around a future migration to Optimizely CMS 13. As a result, upgrades such as Opti ID adoption...

Madhu | Jun 23, 2026 |

Understanding Optimizely Graph: Caching, Webhooks & Avoiding Stale Content (Optimizely SaaS CMS)

📌 Scope: This post covers Optimizely CMS (SaaS) only — using the official @optimizely/cms-sdk and @optimizely/cms-cli packages with Next.js 15. If...

Kiran Patil | Jun 23, 2026 |