Repository with caching

by andrei 25. October 2008 05:45

Here is an idea for a repository which automatically does caching. ProductDetailColumn is a table with very few entries and they are not editable, so it is a very good candidate for caching.

public class ProductDetailColumnRepository
{
  private readonly Repository<ProductDetailColumn> _repository = new Repository<ProductDetailColumn>();
  readonly CacheItemDictionary cache = new CacheItemDictionary();

  private int? _idFilter;
  private int? _columnTypeIdFilter;
  private bool _orderByPosition;

  public ProductDetailColumnRepository InitialiseCriteriaFor(int id)
  {
    ResetVariables();
    _idFilter = id;

    return this;
  }

  private void ResetVariables()
  {
    _idFilter = null;
    _columnTypeIdFilter = null;
    _orderByPosition = false;
  }

  public ProductDetailColumnRepository InitialiseListCriteria()
  {
    ResetVariables();
    return OrderByPosition();
  }

  public ProductDetailColumnRepository OfType(int columnTypeId)
  {
    _columnTypeIdFilter = columnTypeId;

    return this;
  }

  public ProductDetailColumn LoadItem()
  {
    IList<ProductDetailColumn> allProductDetailColumns = GetAllUsingCache();

    return FilterAndSortList(allProductDetailColumns).FirstOrDefault();
  }

  private IList<ProductDetailColumn> GetAllUsingCache()
  {
    IList<ProductDetailColumn> allProductDetailColumns = cache.GetItemIdentifiedBy(CacheKeys.AllProductDetailColumns);

    if (allProductDetailColumns == null)
    {
      allProductDetailColumns = _repository.LoadAll();
      cache.Add(CacheKeys.AllProductDetailColumns, allProductDetailColumns);
    }
    return allProductDetailColumns;
  }

  private IEnumerable<ProductDetailColumn> FilterAndSortList(IEnumerable<ProductDetailColumn> list)
  {
    IEnumerable<ProductDetailColumn> ret = list.ToList();

    if (_columnTypeIdFilter.HasValue)
      ret = ret.Where(p => (int)p.ColumnType == _columnTypeIdFilter.Value);

    if (_idFilter.HasValue)
      ret = ret.Where(p => p.Id == _idFilter);

    if (_orderByPosition)
      ret.OrderBy(p => p.Position);

    return ret;
  }

  public IEnumerable<ProductDetailColumn> LoadList()
  {
    IList<ProductDetailColumn> allProductDetailColumns = GetAllUsingCache();

    return FilterAndSortList(allProductDetailColumns);
  }

  public ProductDetailColumnRepository OrderByPosition()
  {
    _orderByPosition = true;

    return this;
  }
}

 

Here is some sample usage:

ProductDetailColumn col = _productDetailColumnRepository
  .InitialiseListCriteria()
  .OfType((int) enumProductDetailColumn.SubProductColumn)
  .LoadItem();

We are also able to do this:

IEnumerable<ProductDetailColumn> columns = _productDetailColumnRepository.InitialiseListCriteria ( )
  .LoadList ( );

No matter what calls we make and in what order, the repository will make a database call only the first time and use the cache for the following requests.

 

There is one interesting thing to observe. Because of this:

return OrderByPosition();

the returned list will always be ordered by Position.

 

I am using a CacheItemDictionary class, based on a generic dictionary idea from Jean-Paul S. Boodhoo's NothinButDotNetStore application. You can get more implementation details (for IItemKey, for example) from there.

public class CacheItemDictionary
{
    private readonly Cache cache = HttpRuntime.Cache;
    private readonly int _cachingTimeInHours = Constants.Caching.DefaultCachingTimeInHours;

    public CacheItemDictionary ( )
    {
        
    }

    public CacheItemDictionary(int cachingTimeInMinutes)
    {
        _cachingTimeInHours = cachingTimeInMinutes;
    }

    public void Add<ItemToPutInContext> ( IItemKey<ItemToPutInContext> key, ItemToPutInContext item )
    {
        cache.Insert( key.Key, item, null, DateTime.Now.AddHours(_cachingTimeInHours),
            Cache.NoSlidingExpiration );
    }

  public void Add<ItemToPutInContext>(IItemKey<ItemToPutInContext> key, ItemToPutInContext item, int cachingTimeInHours)
  {
    cache.Insert(key.Key, item, null, DateTime.Now.AddHours(cachingTimeInHours), Cache.NoSlidingExpiration);
  }

    public Item GetItemIdentifiedBy<Item> ( IItemKey<Item> key )
    {
        return (Item)cache[key.Key ];
    }
}
 
Technorati Tags: ,,

 

 

Enjoy programming!

 

DDD

I am putting together a set of concept lists for the main programming techniques, which should help developers learning or using them to be more efficient. Here are the techniques in progress:

Please feel free to leave any comments or suggestions which could make these lists more useful for everyone.

 

 

Also, if you are interested in learning these techniques you can try the developer training modules.

Again, please feel free to leave any comments or suggestions which could make the training modules more useful for everyone. We are having great results with them at Akcedo (so they really work), but they can always be improved. Also, if you would like to use the modules or are already using them and you want to discuss about the process feel free to comment and ask questions here.

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.4.5.0