Anders G. Nordby

Senior Web Developer at CGI

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
        })
        .GetResult();
}

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:

CoursePage.LocationPostalName

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
    .Facets;

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

        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:

allLocations

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

Follow

Get every new post delivered to your Inbox.