35 min
Published:
In this next installment of our discussion of ways you’d perform CRUD operations with Sitecore, we’ll discuss how to Read data from Sitecore. In our last post, we discussed how you could use Sitecore Item API, Glass, Fortis and Synthesis to create items within Sitecore. In this post we will focus on the Item API, and in our next session we focus more on the ORM wrappers to read that data. The reason for the split is because the Sitecore Item API is a bare essential in all the other ORM’s (although some of the ORM’s abstract the complexity of the Sitecore Item API away).
When using the Sitecore API to pull items from Sitecore, there is really four ways you would do that: Sitecore Query, Fast Query, Lucene Query, or direct GetItem calls within the ItemProvider.
Generally nowadays you would want to avoid using Sitecore Query to pull data from Sitecore, but sometimes within the Sitecore Content Editor it might make sense, especially when using it as a Source for a Multilist or other type of item field. Below shows some examples of how you might write typical Sitecore Queries. I hope to write a full article on writing Sitecore Queries in the future, even though I think there are better methods for reading sitecore items nowadays, it’s still important to know how to write Sitecore Queries, because they are used all across the Sitecore platform.
A basic Sitecore query:
1$ query:/sitecore/content/#site-1#/*
The example above represents a fairly common Sitecore query that you might create and run. One thing to know is that you must escape hyphen’s in the query, to do so, you would wrap them in the # symbol like you see above.
1$ query:/sitecore/content//*
The example above is similar to the first example, except it ends in //* instead of just /. // will look at the current folder and recursively search every folder underneath that folder for whatever criteria you are searching for. In this example, you would be building a list of items for everything underneath the content item recursively (which is extremely inefficient). The /* will just look for items that are children of the current item and then not look any deeper than that.
1$ query:/sitecore/content//*[@@templateid='{guid}']
In this final example, this showcases how you can recursively search all descendants of the current content folder and filter the results only by items that have a template id that matches the filter that you pass in.
Some other limitations to note about Sitecore Query, is that it can only return a set number of results. By default it would only return 100 results, but obviously you can increase that number by patching the following config setting:
1<setting name="Query.MaxItems>2 <patch:attribute name="value">250</patch:attribute>3</setting>
Fast Query is very similar to Sitecore Query but when working with thousands of items vs. with working with smaller subsets of items (usually less than 100 items) fast query is the better choice. There are however again some limitations of Fast Query. Because of how it works, it will return results as they are found and they will not appear in the order that they are found in the tree. This can cause issues and it’s one of the major reasons why Fast query isn’t that popular as a way to pull data. If you are working with the content tree but can’t use some of the better options such as Lucene that we will describe in a second, and you are just needing all the data, than fast query can be a good option.
Another issue with fast query is that Sitecore Query actually allows for more options to filter results by, whereas Fast Query will limit you on what you can return. The only real difference semantically is that instead of prefixing the query with query:
, you would instead prefix it with fast:
.
This in my opinion is the preferred way of pulling data from your website, especially on your visitor facing portions of your site which typically see a lot more traffic. Lucene is different, it’s actually not really a Sitecore technology, just a marriage between Sitecore and Lucene that allows for a faster way to get items from anywhere in the tree (as long as they’re in the index). The index is a collection of documents that’s built from your tree. Typically as you add content to the tree, items are added to the index (master on save and web index on publish). If you have custom indexes those may vary depending on the index rebuild strategy that you are using.
To start writing queries in lucene, you will need to use the Linq to Lucene provider, so that you can write simple .net linq statements which will be converted into Lucene queries behind the scenes. To get started, you could write something like the following:
1 using (var context = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext())2 {3 // Build Query4 var query = context.GetQueryable<SearchResultItem>();56 // Perform a Search7 query = query.Where(i => i.Name == "Hello World");89 // Materialize the Results10 var results = query.GetResults();11 }
A few things to note from the example above. First is the first line, this line builds a search context using the sitecore_web_index. However you might not always want to use this index. If you want the index to vary depending on the context of the current context item, you could use:
1using (var context = Sitecore.ContentSearch.ContentSearchManager.CreateSearchContext(new Sitecore.ContentSearch.SitecoreIndexableItem(Sitecore.Context.Item)))2{3 // Query Here4}
This alternative allows you to use the context item to determine the index used. So if you are working in the experience editor and it’s pulling data, it would be the master index in that context, and else if you are viewing the website, you would be using the web index.
Secondly, an important topic to discuss is how you might query data that’s in a custom field or template. So from the example above, we used GetQueryable<SearchResultItem>()
. SearchResultItem is a base type that represents common item fields you might want to query from the index. However you might find you need to search on other fields, such as if you had an article template and you needed to search based upon a Category which is an DropList field which stores an ID in sitecore. To do that you would need to create a new POCO class that would represent the data you need to pull. Then you would use a data attribute to map an index field to the property you would define. Something like this for example:
1public class ArticleSearchItem : SearchResultItem2{3 [IndexField("categoryid")]4 [TypeConverter(typeof(IndexFieldIDValueConverter))]5 public ID CategoryId { get; set; }6}
Finally on the last line, you would call query.GetResults(). This method returns an object that has a property called Hits. This represents data found that matches your search request.