C# Batchfile
Latest commit b865fff Feb 11, 2017 @VahidN Console app sample

README.md

EFSecondLevelCache.Core

Entity Framework Core Second Level Caching Library.

Second level caching is a query cache. The results of EF commands will be stored in the cache, so that the same EF commands will retrieve their data from the cache rather than executing them against the database again.

Install via NuGet

To install EFSecondLevelCache.Core, run the following command in the Package Manager Console:

PM> Install-Package EFSecondLevelCache.Core

You can also view the package page on NuGet.

This library also uses the CacheManager.Core, as a highly configurable cache manager. To use its in-memory caching mechanism, add these entries to the project.json file:

{
    "dependencies": {
        "EFSecondLevelCache.Core": "1.0.3-*",
        "CacheManager.Core": "0.9.3",
        "CacheManager.Microsoft.Extensions.Caching.Memory": "0.9.3",
        "CacheManager.Serialization.Json": "0.9.3"
    }
}

And to get the latest versions of these libraries you can run the following command in the Package Manager Console:

PM> Update-Package

Usage

1- Register the required services of EFSecondLevelCache.Core and also CacheManager.Core

namespace EFSecondLevelCache.Core.AspNetCoreSample
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddEFSecondLevelCache();

            services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
            services.AddSingleton(typeof(ICacheManagerConfiguration),
                new CacheManager.Core.ConfigurationBuilder()
                        .WithJsonSerializer()
                        .WithMicrosoftMemoryCacheHandle()
                        .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10))
                        .Build());
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseEFSecondLevelCache();
        }
    }
}

2- Setting up the cache invalidation by overriding the SaveChanges method to prevent stale reads:

namespace EFSecondLevelCache.Core.AspNetCoreSample.DataLayer
{
    public class SampleContext : DbContext
    {
        private readonly IConfigurationRoot _configuration;
        private readonly IEFCacheServiceProvider _cacheServiceProvider;

        public SampleContext(IConfigurationRoot configuration, IEFCacheServiceProvider cacheServiceProvider)
        {
            _configuration = configuration;
            _cacheServiceProvider = cacheServiceProvider;
        }

        public virtual DbSet<Post> Posts { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
        }

        public override int SaveChanges()
        {
            this.ChangeTracker.DetectChanges();
            var changedEntityNames = this.GetChangedEntityNames();

            var result = base.SaveChanges();
            _cacheServiceProvider.InvalidateCacheDependencies(changedEntityNames);

            return result;
        }
    }
}

3- Then to cache the results of the normal queries like:

var products = context.Products.Include(x => x.Tags).FirstOrDefault();

We can use the new Cacheable() extension method:

var products = context.Products.Include(x => x.Tags).Cacheable().FirstOrDefault(); // Async methods are supported too.

Guidance

When to use

Good candidates for query caching are global site settings and public data, such as infrequently changing articles or comments. It can also be beneficial to cache data specific to a user so long as the cache expires frequently enough relative to the size of the user base that memory consuption remains acceptable. Small, per-user data that frequently exceeds the cache's lifetime, such as a user's photo path, is better held in user claims, which are stored in cookies, than in this cache.

Scope

This cache is scoped to the application, not the current user. It does not use session variables. Accordingly, when retriveing cached per-user data, be sure queries in include code such as .Where(x => .... && x.UserId == id).

Invalidation

This cache is updated when an entity is changed (insert, update, or delete) via a DbContext that uses this library. If the database is updated through some other means, such as a stored procedure or trigger, the cache becomes stale.