Friday 16 October 2015

ReSharper and Complex Content Searching

On a recent project, I had to create a more complicated content search that involved a number of parameters, some of which had to be grouped with ands and ors.  In doing this I encountered some issues with Sitecore's implementation of Linq and the use of tools like ReSharper.

I have a number of different filters passed into my search results method, with each search parameter being a list of GUIDs

public static IList<ProductSearchResultItem> GetAllProductsByFilter(
       List<Guid> categories,
       List<Guid> subCategories, List<Guid> brands,
       List<Guid> agesAndStages, List<Guid> features,
       List<Guid> searchTerms, List<Guid> brandCollections,
       List<Guid> products, List<Guid> colors,
       List<Guid> fashions, List<Guid> subBrands,
       bool includeProducts, ProductFilterSortOrder sortOrder,
       int pageNumber, int pageSize, out int count)       
I then need to start building out my predicates, that will enable me to build up my search expression. The issue arises when you do something like:
var query = GetBaseQuery(searchContext);

var predicate = PredicateBuilder.True<productsearchresultitem>();
var predicateCategory = PredicateBuilder.False<ProductSearchResultItem>();

foreach (var category in categories)
{
   var localCategory = category;
   predicateCategory = predicateCategory.Or(p => p.Categories.Contains(localCategory));
}

ReSharper will try to refactor the loop to something like:
 predicateCategory = categories.Aggregate(predicateCategory, (current, localCategory) => current.Or(p => p.Categories.Contains(localCategory)));
The Aggregate extension method is not supported by Linq to Sitecore and will throw an exception when the query is evaluated (ToList()).

To stop this happening you can instruct ReSharper to ignore this by doing the following:
                 
// ReSharper disable LoopCanBeConvertedToQuery
foreach (var category in categories)
{
   var localCategory = category;
   predicateCategory = predicateCategory.Or(p => p.Categories.Contains(localCategory));
}
This will stop ReSharper from suggesting the refactoring from this point in the code.

Another Gotcha I found was when I came to evaluate the expression using:
 query = Queryable.Where(query, predicate);
ReSharper will suggest changing this to use the extension method:
  query = query.Where(predicate);
Which will break Linq to Sitecore.

You can stop this from happening once:
                
// ReSharper disable once InvokeAsExtensionMethod
query = Queryable.Where(query, predicate);
// ReSharper restore LoopCanBeConvertedToQuery

No comments:

Post a Comment