LibrarySites.Banner

Extending Sitecore Query

This blog post explains how you can add custom functions to the query syntax available in the Sitecore ASP.NET web Content Management System (CMS). The Query Analyzer - language/version selection thread on the Sitecore Developer Network (SDN) forums prompted me to write this blog post. For more information about Sitecore query, see Using Sitecore Query on SDN and the blog post Sitecore Query Cheat Sheet.

You can add functions to the Sitecore query syntax, but only where you use the Sitecore.Data.Query.Query class to invoke queries. I am not sure that Sitecore intended developers to extend Sitecore query, so this technique may not feel exactly natural. To extend Sitecore query, create a class that derives from Sitecore.Data.Query.Query, and use your class in place of that default. In your class, override the constructors to call the corresponding base constructors, but add an event handler to the Functions property defined by the Sitecore.Data.Query.Query base class. Sitecore activates your event handler for all function calls; in your event handler, handle your own functions, but call Sitecore.Data.Query.Functions.FunctionCall() for any default functions.

This untested prototype contains the following functions:

  • ContainsIgnoreCase(): Similar to contains(), but not case-sensitively; potentially more efficient than ToLower()
  • ToLower(): Convert a string to lowercase
  • VersionCount(): Retrieve the number of versions of the item in the context language (you can use this to check whether a version exists)

It also contains a web form that lets you evaluate queries using this library, which demonstrates usage of the relevant API.

Note that you do not add an event handler for each function, you add a single handler that dispatches the event to the appropriate handler. If you added multiple handlers, in each one, for functions other than those handled by that handler, you would have to determine to which handler you should pass the event. The reason is that in C#, the return value of an event is that result of the last event handler (for more information about this issue, see the MSDN Deviations blog post Event Handlers returning Values).

As mentioned previously, this approach only works where you can override the Sitecore.Data.Query.Query class, not in the Sitecore.Data.Database.Select*() and Sitecore.Data.Items.Item.Axes.Select*() methods. Sitecore Rocks provides a separate architecture for extending Sitecore query that I have not yet investigated. For more information about Sitecore Rocks, see the blog post Sitecore Differentiating Factors Blog Series: Sitecore Rocks.

  • Hi John,  I've been trying to get this sample working but I'm getting a null reference exception at the following line:  object results = query.Execute();  Do you know what this might be by any chance?  Are there any version specific dependencies here?  I'm using Sitecore 6.5.0 (rev. 120427)   Regards Richard

  • Hi John,  I solved the issue here, it was Context issue.  I'd moved the code to run from a custom agent so I had to use the overload of the Execute method to specify the queryContext as below:  var db = Sitecore.Configuration.Factory.GetDatabase("master"); var queryContext = new Sitecore.Data.Query.QueryContext(db.DataManager); object results = query.Execute(queryContext);   Thanks for all the info in the posts, keep them coming!!  Regards Richard

  • @Richard: Glad to help, and thanks for posting the information and solution!

  • John, would it be possible to leverage this extended code to retrieve the current item name to include in the query? I would like to create folders, with the same name as page items, in a shared content folder. These folders would contain rendering datasource items for the current page. Then using the query to search the shared content sub-folders for the matching folder name.