CRAFTING LINQ QUERIES IN SITECORE CONTENT SEARCH

  • By Andrew Ward
Andrew Ward
If you have had the luxury of getting your hands on the Sitecore content search, I'm confident that you'll join me when I say that it can be described using one word..."AMAZING"!  

There are many ways to approach writing LINQ queries within the content search. I'll cover two here: One quick and easy "static queries" approach and the other, an open dynamic query using the Sitecore PredicateBuilder class. I commonly use both. Here they are:  
 

1# the quick easy way  

 
The example below is fairly simple, it’s going to search the web index for items with a template type of product, it’s going to order its results by the Name property which is one of the default properties the SearchResultsItem exposes. It couldn't be simpler, there are a whole host of properties that you can query, including the ability to add your own.
 
You can also incorporate pagination into the query using .Skip() and .Take() before GetResults() is called. 

using (IProviderSearchContext searchContext = ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext()) 
            { 
                var products = searchContext.GetQueryable() 
                                           .Where(i => i.TemplateName == "Product") //will search for items that have a template type of product 
                                           .OrderBy(i => i.Name) //will order the items by display 
                                           .GetResults(); 
 
            } 


Once you have your product object you can use the products.Hits; property to assign your collection of SearchResultItems to a repeater for consumption of your user, you can also use products.TotalSearchResults; to get the total number of possible results for your query to calculate pagination. 
 
2# reusable dynamic approach (the fun way) 
This is a simple example of what can be achieved with the dynamic approach, using ANDs and ORs to refine our search query to get the results we'd like. We will also be creating smaller queries. I simply provide my method GetLatestContent() with a string searchTerm, a List<ID> of templateIds, a starting point and a number of results to take. 


using System.Collections.Generic; 
using System.Linq; 
using Sitecore.ContentSearch; 
using Sitecore.ContentSearch.Linq; 
using Sitecore.ContentSearch.Linq.Utilities; 
using Sitecore.ContentSearch.SearchTypes; 
using Sitecore.Data; 
 
namespace SitecorePlayground.Web.Code.Search 
{ 
    public class SearchRepository 
    { 
        public SearchResults GetLatestContent(string searchTerm, List templateIds, int skip, int pageSize) 
        { 
            //create new query 
            var query = PredicateBuilder.True(); 
 
            //if we have a search term 
            if (!string.IsNullOrEmpty(searchTerm)) 
            { 
                //search for the content field for the search term, you can also boost your expression by using .Boost(float boost) 
                query = query.And(i => i.Content.Contains(searchTerm)).Boost(5.0f); 
            } 
 
            //if we have any templates 
            if (templateIds.Any()) 
            { 
                var expression = PredicateBuilder.False(); 
 
                //templateIds in this example would contains the template ID  
                //for a News Page && Events Page && Blog Article 
                foreach (ID templateId in templateIds) 
                { 
                    expression = expression.Or(x => x.TemplateId == templateId); 
                } 
 
                //our above OR expression needs to be added to our overall query as an AND 
                query = query.And(expression); 
            } 
 
            //use search context 
            using (IProviderSearchContext searchContext = ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext()) 
            { 
                //return paginated results set 
                return searchContext.GetQueryable() 
                                    .Where(query) 
                                    .OrderBy(i => i.CreatedDate) 
                                    .Skip(skip) 
                                    .Take(pageSize) 
                                    .GetResults(); 
            } 
        } 
    } 
} 


When compiled, the query above will result in the following query being run against your indexes:  
 
(content == searchTerm) && (template == id1 || template == id2 || template == id3) 
 
You may have noticed that I have been sticking to using the default properties of the SearchResultItem, the reason, below is a list of separate blog articles that will get you on your way to creating computed fields and creating your own SearchResultItem (which will allow you to create your own properties that relate to index fields that contain the values from your sitecore fields). You will be able to use these properties with your search queries.  
 
1. Computed fields
2. Search results items
 
scroll back to the top of the current web page