Whether to reference by GUID or Path in Sitecore

Here is an interesting debate – whether to use GUIDs or Paths to reference Items in Sitecore.

There are advantages and disadvantages to both routes:

By GUID: If you reference an Item by GUID it will mean that you can move it around the Sitecore tree and even rename it without your code breaking. The caveat with this method is that a GUID is not as representative as a path in giving an indication of what the Item is.

To find its path, place the GUID in the Sitecore search, then mouse over to find the path.

Find GUID

By Path: If you reference an Item by path it means you can read the Item’s location easily, however, if you move it around in the tree or rename it, the code will break.

 

My suggestions for referencing an Item are in the following order:

  1. Try to add the Item you want to reference as a link from a field in another important, stationary Item in Sitecore. For example, say you wanted to link to a Meta Data folder in your tree, you could create a field in your Site root called “Meta Data” which was a link field to your Meta Data folder.If this doesn’t apply…
     
  2. Use a GUID to reference your item, and some sort of comment in the code to give an idea as to what the GUID relates to.Next best…
     
  3.  Use a path to reference your item. It would be beneficial to accompany the code with some sort of NUnit Integration Test which would alert you if the path is not there.

I did come up with an alternative which offers slight benefit to the second and third options above and decided to throw it up onto my blog incase any one else found it interesting. It works in a way similar to ConfigurationManager.AppSettings dictionary, in that you can pass it a key name and it will return you a value. However in this case, using Sitecore Templates, we create a GUID Mapping template that will model a name value pair mapping. Where the mapping is a link to a Sitecore Item. So effectively we would say to GUIDManager that we wanted the GUID for the “Meta Data” item and if we had mapped this in Sitecore, it would return us the Meta Data GUID. (We could even make this return an object if we really wanted).

Ultimately what we get from this class is the flexibility of the GUID in that the underlying link can move round the tree and be renamed and not break our code, as well as having an easy to read, meaningful name.

I’ll post up some Sitecore configuration pictures next week, to explain the GUID Mapping template.

    public static class GUIDManager
    {
        /// <summary>
        /// This method will get the GUID for the given name
        /// </summary>
        /// <param name="name">The name to get</param>
        /// <returns>The associated GUID</returns>
        public static string GetGUID(string name)
        {
            if(string.IsNullOrEmpty(name))
            {
                return null;
            }

            try
            {
                string guidStorageLocation = ConfigurationManager.AppSettings["GUIDStorageLocation"];

                // Check to see whether the storage location has been set
                if(!string.IsNullOrEmpty(guidStorageLocation))
                {
                    // Check to see whether the storage item exists
                    Database database = Sitecore.Data.Database.GetDatabase("master");

                    Item guidStorageItem = database.GetItem(new ID(guidStorageLocation));
                    
                    if(guidStorageItem != null)
                    {
                        Item guidMapping = guidStorageItem.Children[name];

                        // Check to see whether the specified mapping exists
                        if(guidMapping != null)
                        {
                            // Return the GUID from the mapping
                            return guidMapping["GUID"];
                        }
                    }
                }

                return null;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }

Screenshot of an example GUID Mapping

Screenshot of Sitecore

Screenshot of a GUID Mapping template

Screenshot of Sitecore

Sitecore and Item transactions

As I have been doing a lot of work with bulk data insertion and manipulation within Sitecore, coupled with the belief that I don’t think Sitecore offers you the ability to use transactions, I have created my own stand in, simple transaction class.

It utilizes generics and .Net’s disposable interface http://msdn.microsoft.com/en-us/library/system.idisposable.aspx to achieve an easy to read transaction.

If you look at the following code, the first segment shows you how to use the Transaction.cs, the second segment is Transaction.cs. You can see we wrap the transaction in a using statement, which will call the rollback delegate if an exception is thrown at any point. Or alternatively we can call transaction.dispose() which will roll back the transaction also.

How to use Transaction.cs

    public class UtilityMethods
    {
        private Transaction<Item> transaction;

        public void AddChildItems(Item parentItem, string newChildName, TemplateID childTemplateID, int numberOfChildrenToAdd)
        {
            using(transaction = new Transaction<Item>(Rollback))
            {
                for (int i = 0; i < numberOfChildrenToAdd; i++)
                {
                    Item insertedChild = parentItem.Add(newChildName, childTemplateID);
                    transaction.TransactionableItems.Add(insertedChild);
                }
            }
        }

        public void Rollback()
        {
            using (new SecurityDisabler())
            {
                if (transaction != null && transaction.TransactionableItems.Count > 0)
                {
                    foreach (Item item in transaction.TransactionableItems)
                    {
                        try
                        {
                            item.Delete();
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }
                }
            }
        }
    }

Transaction.cs

    /// <summary>
    /// This class models a transaction
    /// </summary>
    /// <example>
    /// using(Transaction transaction = new Transaction(// Provide delegate to handle rollback here))
    /// {
    ///     // Sitecore insert
    ///     // Sitecore update
    ///     // Sitecore insert
    ///     transaction.Commit();
    /// }
    /// </example>
    public class Transaction<T> : IDisposable
    {
        public delegate void RollBack();

        private readonly RollBack rollBack;
        private bool isCommited;
        private readonly List<T> transactionItems = new List<T>();

        /// <summary>
        /// Public constructor
        /// </summary>
        ///
<param name="rollBack">A method to use to rollback with</param>
        public Transaction(RollBack rollBack)
        {
            this.rollBack = rollBack;
        }

        /// <summary>
        /// Handles the dispose call
        /// </summary>
        public void Dispose()
        {
            // If the transaction is not commited
            // and object is disposing, rollback
            if (!isCommited && rollBack != null)
            {
                rollBack();
            }
        }

        /// <summary>
        /// Sets the commited flag to true,
        /// rollback cannot happen after commit is called
        /// </summary>
        public void Commit()
        {
            isCommited = true;

            transactionItems.Clear();
        }

        /// <summary>
        /// Gets the list of transactionable Items
        /// </summary>
        public List<T> TransactionableItems
        {
            get { return transactionItems; }
        }

        /// <summary>
        /// Returns whether or not the transaction was comitted
        /// </summary>
        public bool WasCommited
        {
            get { return isCommited; }
        }
    }