Working with Sitecore 7 Search

In this tutorial we will look at how we can use Glass.Mapper with the new Sitecore 7 search API.

Supporting Glass.Mapper.Sc 3.1.0 and onwards.

The integration with Sitecore 7 search use the new SitecoreService.Map method that allows you to map Sitecore data to any existing object.

One requirement is that the existing object must have a configuration that has already been loaded by Glass.Mapper, i.e. On Demand mapping won't work with this method. I will look at how we can map both a class that inherits the SearchResultItem class and also a raw class.

Using the SearchResultItem

Lets assume we have the following class that represents our search results:

        public class MySearchItem : SearchResultItem
        {
            public virtual string Url { get; set; }

            public virtual string RichTextContent { get; set; }
        }

The class inherits from the Sitecore.ContentSearch.SearchTypes.SearchResultItem and defines two additional properties. The Url is the items Url which we don't want to index and the RichTextContent which points to a Rich Text field.

First we have to configure it, because we can't add attributes to the SearchResultItem we have to use fluent configuration, add this to your GlassMapperScCustom.GlassLoaders method:

public static IConfigurationLoader[] GlassLoaders(){
   var attributes = new SitecoreAttributeConfigurationLoader("glass.sitecore7");
                
   var loader = new SitecoreFluentConfigurationLoader();
   var config = loader.Add<MySearchItem>();
    
                
   config.Id(x => x.ItemId);
   config.Info(x => x.Language).InfoType(SitecoreInfoType.Language);
   config.Info(x => x.Version).InfoType(SitecoreInfoType.Version);

   config.Field(x => x.RichTextContent);
   config.Info(x => x.Url).InfoType(SitecoreInfoType.Url);
   return new IConfigurationLoader[]{attributes, loader};
}

After the standard configuration loader we configure the item Id, Language and Version. I would recommended that you always map these three properties, this will ensure that Glass.Mapper is able to find the exact item to return.

After this we can map the additional Sitecore properties as we would normally. With our code we can then call the ISitecoreService.Map method:

            var index = ContentSearchManager.GetIndex("sitecore_master_index");
            var sitecoreService = new SitecoreService("master");

            using (var context = index.CreateSearchContext())
            {
                var results = context.GetQueryable<MySearchItem>()
                        .Where(item => item.TemplateName == "Sample Item")
                        .Take(10)
                        .ToList();

                foreach (var result in results)
                {
                    sitecoreService.Map(result);
                }
            }

Notice that we query the index first and then pass it to Glass to do the final mapping, we choose this root because it gives you more control over when you want items to be passed to Glass.

Using a Custom Result Class

The other way to get results from Sitecore 7 search API is just to use your own class that doesn't inherit from SearchResultItem. Lets take this example class:

        [SitecoreType]
        public class MySearchItem
        {
            [SitecoreId]
            [IndexField("_id")]
            public virtual Guid Id { get; set; }

            [SitecoreInfo(SitecoreInfoType.Language)]
            [IndexField("_language")]
            public virtual string Language { get; set; }

            [TypeConverter(typeof(IndexFieldItemUriValueConverter))]
            [XmlIgnore]
            [IndexField("_uniqueid")]
            public virtual ItemUri Uri { get; set; }

            [SitecoreInfo(SitecoreInfoType.Version)]
            public virtual int Version
            {
                get
                {
                    return Uri == null ? 0 : Uri.Version.Number;
                }
            }

            [SitecoreField]
            public virtual string RichTextContent { get; set; }

            [SitecoreInfo(SitecoreInfoType.Url, UrlOptions = SitecoreInfoUrlOptions.LanguageEmbeddingNever)]
            public virtual string Url { get; set; }
        }

You should setup your class to have the Id, Language, Uri and Version properties as shown above, without all these properties Glass.Mapper won't be able to find the appropriate item when you try and retrieve it from Sitecore. You can then map additional fields as you normally would using IndexFields or Glass.Mapper attributes.

The following code shows how we can pull data from Sitecore by using the ISitecoreService.Map method:

            var index = ContentSearchManager.GetIndex("sitecore_master_index");
            var sitecoreService = new SitecoreService("master");

            using (var context = index.CreateSearchContext())
            {
                var results = context.GetQueryable<MySearchItem>()
                        .Take(10)
                        .ToList();

                foreach (var result in results)
                {
                    sitecoreService.Map(result);
                }
            }

Summary

The ISitecoreService.Map method can be used with any object that has been partially populated and defines a property that represents the Sitecore item ID. The ID property must contain the ID of the target item. Adding the Language and Version properties allows Glass.Mapper to better identify the item you want to map to.

You can use the ISitecoreService.Map method to merge objects from other data sources, not just Sitecore 7 Search.