Anders G. Nordby

Lead Software Engineer at Sopra Steria

Monthly Archives: September 2014

EPiServer Find: TermsFacets and Projections

TermsFacets are pretty nice, and so are projections, but you can easily find yourself in a situation where they seem to not work together. The TermsFacets build facets we can use to provide navigation and filtering for the end user, and the projection gives us lightweight objects to work with. Great, but we might run into trouble… Let’s take a look at this example:

public SearchResults<CourseListItem> GetAllCourses() 
    return _client.Search<CourseWithMetaData>()
        .Filter(x => x.IsArchived.Match(false))
        .TermsFacetFor(x => x.CoursePage.LocationPostalName)
        .Select(x => new CourseListItem
            Title = x.CoursePage.Name,
            Url = x.CoursePage.LinkURL,
            StartTime = x.CoursePage.StartTime,
            Location = x.CoursePage.LocationPostalName

If we were aware that EPiServer Find will build a key based on reflection, we could see the problem already… 🙂 But let’s say we didn’t know that… Then we would get a surprise when we try to get the facets for the search.

var allCourses = _searchDelegate.GetAllCourses();
var locationFacets = allCourses
    .TermsFacetFor(x => x.Location);

The value of locationFacets will be null here! Why?

The line .TermsFacetFor(x => x.CoursePage.LocationPostalName) will create the key “CoursePage.LocationPostalName” when storing the facets. However, we’re trying to get them out again with the key “Location”, which obviously returns a null value in this example.

That the facets are there, but stored with a different key, is easy to see using the debugger:


Now, my simple idea for a solution is to loop through the list of facets until I find the correct one. In my example, this is how I do it:

var allLocations = new List<string>();

var allCourses = _searchDelegate.GetAllCourses();
var allFacets = allCourses

if (allFacets != null)
    foreach (var facet in allFacets)
        if (facet.Name != "CoursePage.LocationPostalName")

        var theFacet = (IEnumerable<TermCount>)facet;
        allLocations.AddRange(theFacet.Select(x => x.Term));

And as you can see, I now get access to the TermsFacets that I created:


If anyone has a better way to accomplish this, please let me know!

UPDATE from Per Magne Skuseth:
There is actually a way to accomplish this using the standard API. You could use .TermsFacetFor<T>.
So, in your case when you are retrieving the facets, you should do something like

.TermsFacetFor<CourseWithMetaData>(x => x.CoursePage.LocationPostalName)