Creating the base data provider class

The Sitefinity modules are based on the provider pattern. They use data providers for their data access layer. A good practice, when creating a data provider, is to create a base abstract class that provides a common implementation for the provider. Then use it to implement concrete data providers for the different data stores. This spares you of writing the common part of the code for each of the concrete implementations. Even if you intend to have only one data provider in your module, consider using this base provider class.

To create the abstract base class for the data provider, perform the following:

  1. From the context menu of the folder Data in the LocationsModule project, click Add » Class.
  2. Name the class file LocationsDataProvider.cs and click Add.
  3. Open the file LocationsDataProvider.cs.
  4. Add the following using statments:

    • using Telerik.Sitefinity.Modules.GenericContent;
    • using System.Collections;
    • using LocationsModule.Model;
    • using Telerik.Sitefinity.Data.Linq.Dynamic;
    • using Telerik.Sitefinity.Model;
    • using Telerik.Sitefinity.GenericContent.Model;
  5. Make the LocationsDataProvider class inherit the ContentDataProviderBase class:

    public abstract class LocationsDataProvider : ContentDataProviderBase
    {
    }

  6. Implement the ContentDataProviderBase class.

    To implement it, you must have the following members in the LocationsDataProvider class:

    • RootKey - in this property you must store an identifier for the provider.
    • GetParentTypeFor - this method is used for modules with parent-child relationships, such as Lists and List Items, and Blogsand Blog Posts. If the module doesn't have such relationship, you must return null.
    • GetUrlTypeFor - in this method, you must return the UrlData implementation created for the persistant class.
    • GetKnownTypes - in this method you must return a list of types, that your provider handles.
    • GetItemsByTaxon - this method allows you to retrieve LocationItem objects by tag or category using the Sitefinity taxonomy system.
    • GetItemFromUrl - this method allows you to retrieve LocationItem objects by their urls.

    Following is the code for the implementation of these members:

    public override IEnumerable GetItemsByTaxon(Guid taxonId, bool isSingleTaxon,
          string propertyName, Type itemType, string filterExpression, string orderExpression,
          int skip, int take, ref int? totalCount)
    {
        if (itemType == typeof(LocationItemUrlData))
        {
            this.CurrentTaxonomyProperty = propertyName;
            var query = (IQueryable<LocationItem>)GetItems(itemType, filterExpression, string.Empty, skip, take, ref totalCount);
            if (isSingleTaxon)
            {
                var query0 = from i in query
                                where (Guid)i.GetValue(this.CurrentTaxonomyProperty) == taxonId
                                select i;
                if (!string.IsNullOrEmpty(orderExpression))
                    return query0.OrderBy(orderExpression);
                return query0;
            }
            else
            {
                var query1 = from i in query
                                where ((IList)i.GetValue(this.CurrentTaxonomyProperty)).Contains(taxonId)
                                select i;
                if (!string.IsNullOrEmpty(orderExpression))
                    return query1.OrderBy(orderExpression);
                return query1;
            }
        }
        throw GetInvalidItemTypeException(itemType, this.GetKnownTypes());
    }
     
    public override IDataItem GetItemFromUrl(Type itemType, string url, bool published, out string redirectUrl)
    {
        if (itemType == null)
            throw new ArgumentNullException("itemType");
        if (String.IsNullOrEmpty(url))
            throw new ArgumentNullException("Url");
     
        var urlType = this.GetUrlTypeFor(itemType);
     
        var    urlData = this.GetUrls(urlType).Where(u => u.Url == url).FirstOrDefault();
     
     
        if (urlData != null)
        {
            var item = urlData.Parent;
     
            if (urlData.RedirectToDefault)
                redirectUrl = this.GetItemUrl((ILocatable)item, CultureInfo.GetCultureInfo(urlData.Culture));
            else
                redirectUrl = null;
            if (item != null)
                item.Provider = this;
            return item;
        }
        redirectUrl = null;
        return null;
    }
     
    public override Type GetParentTypeFor(Type contentType)
    {
        return null;
    }
     
    public override Type GetUrlTypeFor(Type itemType)
    {
        if (itemType == typeof(LocationItem))
        {
            return typeof(LocationItemUrlData);
        }
     
        throw GetInvalidItemTypeException(itemType, this.GetKnownTypes());
    }
     
    public override Type[] GetKnownTypes()
    {
        return new[] { typeof(LocationItem) };
    }
     
    public override string RootKey
    {
        get
        {
            return "LocaitionsDataProvider";
        }
    }

  7. Create abstract methods for the following operations:

    • Create location
    • Get location
    • Get locations
    • Delete locations

    Following is the definitions for the methods:

    public abstract LocationItem CreateLocation();
     
    public abstract LocationItem CreateLocation(Guid id);
     
    public abstract LocationItem GetLocation(Guid id);
     
    public abstract IQueryable<LocationItem> GetLocations();
     
    public abstract void DeleteLocation(LocationItem location);

  8. Override the respective methods of the ContentDataProviderBase class and call the abstract methods from them.

    public override object GetItemOrDefault(Type itemType, Guid id)
    {
        if (itemType == typeof(Comment))
        {
            return this.GetComments().Where(c => c.Id == id).FirstOrDefault();
        }
     
        if (itemType == typeof(LocationItem))
            return this.GetLocations().Where(n => n.Id == id).FirstOrDefault();
     
        return base.GetItemOrDefault(itemType, id);
    }
     
    public override object CreateItem(Type itemType, Guid id)
    {
        if (itemType == null)
            throw new ArgumentNullException("itemType");
     
        if (itemType == typeof(LocationItem))
        {
            return this.CreateLocation(id);
        }
     
        throw GetInvalidItemTypeException(itemType, this.GetKnownTypes());
    }
     
    public override object GetItem(Type itemType, Guid id)
    {
        if (itemType == null)
            throw new ArgumentNullException("itemType");
     
        if (itemType == typeof(LocationItem))
            return this.GetLocation(id);
     
        return base.GetItem(itemType, id);
    }
     
    public override IEnumerable GetItems(Type itemType, string filterExpression,
        string orderExpression, int skip, int take, ref int? totalCount)
    {
        if (itemType == null)
            throw new ArgumentNullException("itemType");
     
        if (itemType == typeof(LocationItem))
        {
            return SetExpressions(this.GetLocations(), filterExpression, orderExpression,
                skip, take, ref totalCount);
        }
     
        if (itemType == typeof(Comment))
        {
            return SetExpressions(this.GetComments(), filterExpression, orderExpression,
                skip, take, ref totalCount);
        }
     
        throw GetInvalidItemTypeException(itemType, this.GetKnownTypes());
    }
     
    public override void DeleteItem(object item)
    {
        if (item.GetType() == typeof(LocationItem))
        {
            this.DeleteLocation((LocationItem)item);
        }
    }

    In the overrides of the GetItems and the GetItemOrDefault methods, you must check for whether the item type is Comment.

Related topics:

Feedback

How useful is this article?

Tell us more

Submit
Your message was successfully sent.

We appreciate your feedback.

Your message could not be sent.

OK