The aim of this post is to highlight some pitfalls I have run into in the past when working with the Sitecore API. Hopefully some ideas demonstrated here will help people avoid some common mistakes when programming with Sitecore.
Over time I’d like this list to grow so if anyone has any feedback or suggestions for more items, please let me know.
For each item I will highlight some examples of where I have seen the mistakes and how they can best be avoided.
- Direct database access
- Expensive content queries
1. Direct database access
There are several ways to get a reference to a Sitecore database. Note, these are defined within the config (<databases>). In the following example, the first 2 items get a specific database, the last the context database.
1 2 3 4 |
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master"); Sitecore.Data.Database web = Sitecore.Configuration.Factory.GetDatabase("web"); Sitecore.Data.Database contextDatabase = Sitecore.Context.Database; |
Why is this bad?
In larger Sitecore builds one of the common tasks is to run through the ideas stored in the following guides on the sdn: security hardening and configuring production environments.
One of key steps in these documents is that the content delivery site only has a reference to the web database. Typically you would have an independent content authoring environment which has references to core, master and web. In this setup, if your code has a direct reference to master, you will get an exception since master doesnt exist.
When might you want to do this?
It may be that in certain circumstances you do want to target a specific database. Consider an import routine. In this example you would want to ensure that new items are only added to master – note you would need to ensure the import routine is run from an environment which can access the master database.
2. Expensive content queries
Sitecore.Data.Items.ItemAxes exposes a set of methods which can be used to drill up and down through the content tree. Some examples of this are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
namespace Sitecore.Data.Items { // Summary: // Provides access to other items relative to a source item. // // Remarks: // Implements the Sitecore.Data.Items.Item.Axes property. // You should never instantiate this class. public class ItemAxes { ... // Summary: // Gets an ancestor item. // // Parameters: // itemID: // The item ID. // // includeSelf: // if set to true this instance is include self. // // Returns: // The ancestor. public Item GetAncestor(ID itemID, bool includeSelf); // Summary: // Gets all ancestors. // // Returns: // The ancestors. public Item[] GetAncestors(); // // Summary: // Gets a child item. ... // // Summary: // Gets a list of items that is in descendant axis of the source item. // // Returns: // The descendants. public Item[] GetDescendants(); } } |
Within your sublayouts you could then call eg:
1 |
Sitecore.Data.Items.Item[] descendants = Sitecore.Context.Item.Axes.GetDescendants(); |
Why is this bad?
If your content tree contains thousands of content items and you call GetDescendants from the root node – you will effectively be loading every single item in the tree – I can guarantee the bigger the tree, the slower this will go!
When might you want to do this?
If you are comfortable that the result of a descendants call will expose a controlled set of nodes then you may find them more useful than querying direct children. An example of this is if folders are used in the structure you are querying.
Where might you make this mistake?
A typical place I have seen this implemented is building footer navigation. Consider the following: ‘A developer understands your template structure and sees there is a common base template for each page so adds a new checkbox ‘Show in footer navigation’. In the footer control they then start at the home node calling GetDescendants, checking each item for the new checkbox.‘
What can I do instead?
In the footer example, try to consider alternative solutions for defining which items should be shown in the footer. How about a configuration area of the content tree where the footer navigation is defined as its own node (and children if needed). Your descendants call could then target these specific items.
Other alternatives are using shallower axes for your queries for example: direct children or siblings.