RCommon
HomeGitHub
  • Introduction
  • Common Scenarios
  • Getting Started
    • Running Examples
    • Roadmap
    • Releases
      • 1.0.1.75
      • 1.0.2.0
      • 2.0.0
      • 2.1.0
  • Topics
    • Fundamentals
      • Configuration
      • Logging
      • GUID Generation
      • Time and Date
      • Emailing
        • SMTP Email
        • SendGrid Email API
      • Data Transfer Objects
        • Pagination
      • Security
        • Current User
        • Claims
      • Events
        • Transactional Events
        • Synchronous Events
        • Asynchronous Events
        • Producers
        • Subscribers
      • Validation
        • Fluent Validation
      • Caching
        • Dynamically Compiled Expressions
        • Persistence Caching
        • Caching Services
        • Redis & Valkey
        • Memory Cache
      • Serialization
        • JSON.NET
        • System.Text.Json
    • Patterns
      • Specification
      • Mediator
        • MediatR
          • Validator Behavior
          • Unit of Work Behavior
          • Logging Behavior
      • CQRS
        • Commands
        • Queries
      • Persistence
        • Repository
          • Entity Framework Core
          • Dapper
          • Linq2Db
        • Transactions
          • Unit of Work
      • Event Bus
        • In Memory
        • MediatR
        • Wolverine
      • Message Bus
        • MassTransit
        • Wolverine
    • Architecture
      • Overview
      • Microservices
      • Clean Architecture
      • Event Driven Architecture
  • Examples
    • Clean Architecture
    • CQRS
    • Mediator: MediatR
    • Event Handling: In Memory
    • Event Handling: MediatR
    • Event Handling: MassTransit
    • Event Handling: Wolverine
    • Validation: Fluent Validation
Powered by GitBook
On this page
  • Configuration
  • Usage
  • Behind the Scenes
  1. Topics
  2. Fundamentals
  3. Caching

Persistence Caching

Caching persistence data in RCommon

Occasionally there is the need to cache data that is coming from your persistence layer so that you can avoid hitting your data store repeatedly for data that is commonly used. RCommon provides a proxy for all repository implementations available in RCommon which allows you to use the repository pattern in conjunction with caching services.

Configuration

Note the usage of "ef.AddInMemoryPersistenceCaching" in the configuration below. This will configure the caching repository interfaces for you to use.

var host = Host.CreateDefaultBuilder(args)
                .ConfigureServices(services =>
                {
                    // Configure RCommon
                    services.AddRCommon()
                        .WithPersistence<EFCorePerisistenceBuilder>(ef => // Repository/ORM configuration. We could easily swap out to Linq2Db without impact to domain service up through the stack
                        {
                            // Add all the DbContexts here
                            ef.AddDbContext<TestDbContext>("TestDbContext", ef =>
                            {
                                ef.UseSqlServer(config.GetConnectionString("TestDbContext"));
                            });
                            ef.AddInMemoryPersistenceCaching(); // This gives us access to the caching repository interfaces/implementations
                        })
                        // You still need to configure this as well!
                        .WithMemoryCaching<InMemoryCachingBuilder>(cache =>
                        {
                            cache.Configure(x =>
                            {
                                x.ExpirationScanFrequency = TimeSpan.FromMinutes(1);
                            });
                        });
                }).Build();

It is still important that you configure caching in addition to adding persistence caching since that is what implements the caching abstractions.

Usage

public class TestApplicationService : ITestApplicationService
{
    private readonly ICachingGraphRepository<Customer> _customerRepository;

    public TestApplicationService(ICachingGraphRepository<Customer> customerRepository)
    {
        _customerRepository = customerRepository;
        _customerRepository.DataStoreName = "TestDbContext";
    }

    public async Task<ICollection<Customer>> GetCustomers(object cacheKey)
    {
        return await _customerRepository.FindAsync(cacheKey, x => x.LastName == "Potter");
    }
}

Behind the Scenes

This is what is happening behind the scenes in the caching repository proxy

public class CachingGraphRepository<TEntity> : ICachingGraphRepository<TEntity>
    where TEntity : class, IBusinessEntity
{
    private readonly IGraphRepository<TEntity> _repository;
    private readonly ICacheService _cacheService;

    public CachingGraphRepository(IGraphRepository<TEntity> repository, ICommonFactory<PersistenceCachingStrategy, ICacheService> cacheFactory)
    {
        _repository = repository;
        _cacheService = cacheFactory.Create(PersistenceCachingStrategy.Default);
    }

    public async Task<IPaginatedList<TEntity>> FindAsync(object cacheKey, Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity,
        object>> orderByExpression, bool orderByAscending, int pageNumber = 1, int pageSize = 0, CancellationToken token = default)
    {
        var data = await _cacheService.GetOrCreateAsync(cacheKey, 
            async () => await _repository.FindAsync(expression, orderByExpression, orderByAscending, pageNumber, pageSize, token));
        return await data;
    }
    
    public async Task<IPaginatedList<TEntity>> FindAsync(object cacheKey, IPagedSpecification<TEntity> specification, CancellationToken token = default)
    {
        var data = await _cacheService.GetOrCreateAsync(cacheKey,
            async () => await _repository.FindAsync(specification, token));
        return await data;
    }
    
    public async Task<ICollection<TEntity>> FindAsync(object cacheKey, ISpecification<TEntity> specification, CancellationToken token = default)
    {
        var data = await _cacheService.GetOrCreateAsync(cacheKey,
             async () => await _repository.FindAsync(specification, token));
        return await data;
    }
    
    public async Task<ICollection<TEntity>> FindAsync(object cacheKey, Expression<Func<TEntity, bool>> expression, CancellationToken token = default)
    {
        var data = await _cacheService.GetOrCreateAsync(cacheKey,
            async () => await _repository.FindAsync(expression, token));
        return await data;
    }
PreviousDynamically Compiled ExpressionsNextCaching Services

Last updated 6 months ago