Caching

Jun 23, 2015 at 7:32 PM
in your documentation, you have a section with this title :
How to...
Adding caching to your application

Is it possible for you to illustrate me how make it whit nrepository ? I want implement a redis caching for eliminate a back and forth into the db,

Thanks
Coordinator
Jun 25, 2015 at 7:41 PM
Not used redis but if you want a simple level 2 cache you could try something like this:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Runtime.Caching;
using Northwind.Domain.Core.Entities;
using NRepository.Core.Query;

public class EfCacheableInterceptor : IQueryInterceptor
{
    private static readonly object SyncObject = new object();
    private static readonly MemoryCache Cache = MemoryCache.Default;
    private static readonly IEnumerable<Type> _CacheableTypes = new[]
    {
        // Your entities here
        typeof(Customer)
    };

    public IQueryable<T> Query<T>(IQueryRepository repository, IQueryable<T> query, object additionalQueryData) where T : class
    {
        // It's not a cachable type
        if (!_CacheableTypes.Contains(typeof(T)))
            return query;

        var key = typeof(T).AssemblyQualifiedName;
        var items = Cache.Get(key);
        
        // Is it already cached
        if (items != null)
            return (IQueryable<T>)items;

        lock(SyncObject)
        {
            items = Cache.Get(key);
            if (items == null)
            {
                // if your not generating proxies you can use the following :
                // items = repository.GetEntities<T>(new AsNoTrackingQueryStrategy()).ToArray().AsQueryable();

                // Required so you don't put proxied entities into the cache (
                var dbContext = (DbContext)Activator.CreateInstance(repository.ObjectContext.GetType());
                dbContext.Configuration.ProxyCreationEnabled = false;
                items = dbContext.Set<T>().AsNoTracking().ToArray().AsQueryable();

                Cache.Add(key, items, new CacheItemPolicy());
             }

            return (IQueryable<T>)items;
        }
    }
}
and then in your DI config use:
    container.RegisterType<IQueryRepository, EntityFrameworkQueryRepository>(
        new InjectionConstructor(
            typeof(NRepository_NorthwindContext),
            typeof(EfCacheableInterceptor)));
Jun 25, 2015 at 8:56 PM
is it possible to use this with IRepository ? I use a cache for an update too. Also, I scary that if i use IQueryRepository, i has the same problem that other day https://nrepository.codeplex.com/discussions/639808
Coordinator
Jun 26, 2015 at 12:26 PM
Yeah should be fine with the IRepository interface. Just be aware though that if you update any object type that you've added to the cache you won't b able to retrieve that updated value until the cache expires.
Jun 26, 2015 at 5:49 PM
On the shares of update, I find my cache object by its ID, I make the changes, and after I update my cache and the database.

For cons, I have not found the IRepositoryInterceptor interface. How do I make the same thing that IQueryInterceptor but for IRepository?
Coordinator
Jun 28, 2015 at 6:58 PM
You can use the DefaultRepositoryInterceptor class - this takes any of the interceptors (query or command). See below for example of unity config
container.RegisterType<IRepository, EntityFrameworkRepository>(
    new InjectionConstructor(
        typeof(NRepository_NorthwindContext),
        typeof(DefaultRepositoryInterceptors)));


container.RegisterType<DefaultRepositoryInterceptors>(new InjectionConstructor(typeof(EfCacheableInterceptor)));