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 ];
}
}