Skip to content

How to create Facets

Shawn (work acct) edited this page Aug 2, 2013 · 1 revision

Facets provide a standardized way to pre-package commonly used queries in an easy-to-use object that can be passed to the data retrieval method. The facet class design utilizes two advanced programming concepts to accomplish this:

Each facet class encapsulates the appropriate query expression as it applies to the specified LINQ Entity (using Generics). Custom constructors can be defined to provide additional setup, configuration and/or information needed to provide the appropriate query. This document provides a brief overview in creating additional custom facets by walking through the process of creating a facet to only retrieve Sections for a specific YearQuarter ID.

Since this facet is going to be querying Section records, we start by implementing the ISectionFacet interface:

public class YearQuarterIDFacet : ISectionFacet
{
  public Expression<Func<T, bool>> GetFilter<T>(DbContext dbContext)
         where T : SectionEntity
  {
  }
}

ISectionFacet defines one method - GetFilter(). This method will be called by the OdsRepository when it builds the query needed to retrieve the records requested by a GetSections() call. Notice that GetFilter() returns an Expression<Func<T, bool>>. If you've looked closely at the extension methods for LINQ this may look familiar: The .Where() method also takes an Expression of type Func - which in turn is of type Generic (T) and bool. T is a common placeholder for Generic objects. It means roughly "any object of the type(s) specified", with the type(s) allowed being identified by using the where keyword:

where T : SectionEntity

The statement above basically says that T can be used anywhere in the method signature and body, where you would normally specify SectionEntity. So the translated method signature would look something like this (note: this translation would only occur internally - you would never see this actual signature):

Expression<Func<SectionEntity, bool>> GetFilter<SectionEntity>(DbContext, dbContext)

When used in conjunction with a LINQ .Where() method, the Expression is usually represented using the lambda operator:

collectionOfSectionEntityRecords.Where(s => s.YearQuarterID == "B122");

So the GetFilter() method in our new facet object needs to return the same type of Expression:

public class YearQuarterIDFacet : ISectionFacet
{
  public Expression<Func<T, bool>> GetFilter<T>(DbContext dbContext)
         where T : SectionEntity
  {
    return s => s.YearQuarterID == "B122";
  }
}

That's really all there is to it. At this point we have a fully-functioning facet that can be added to the list of facet objects being passed to a GetSections() call. Of course, a facet that always (and only) filters on the same value isn't much use, so lets make it a little more dynamic. For this facet we can add a constructor which allows us to specify the YearQuarter ID we want to filter on:

public class YearQuarterIDFacet : ISectionFacet
{
  private string _yearQuarterID;

  // Constructor
  public YearQuarterIDFacet(string yrqID)
  {
    _yearQuarterID = yrqID;
  }

  public Expression<Func<T, bool>> GetFilter<T>(DbContext dbContext)
         where T : SectionEntity
  {
    return s => s.YearQuarterID == _yearQuarterID;
  }
}

And there you have it! A custom ISectionFacet object that allows you to filter the query to only include records that match the YearQuarter ID. Use your new custom facet just like any of the other facet objects:

// ...

IList<ISectionFacet> facets = new List<ISectionFacet>();
facets.Add( new YearQuarterIDFacet("B122") );

IList<Sections> sections = repository.GetSections( facets );

// ...