Entity Cache

ABP provides an entity caching system that works on top of the distributed caching system. It does the following operations on behalf of you:

  • Gets the entity from the database (by using the repositories) in its first call and then gets it from the cache in subsequent calls.
  • Automatically invalidates the cached entity if the entity is updated or deleted. Thus, it will be retrieved from the database in the next call and will be re-cached.

Caching Entity Objects

IEntityCache<TEntityCacheItem, TKey> is a simple service provided by the ABP for caching entities. Assume that you have a Product entity as shown below:

public class Product : AggregateRoot<Guid>
{
    public string Name { get; set; }
    public string Description { get; set; }
    public float Price { get; set; }
    public int StockCount { get; set; }
}

If you want to cache this entity, you should first configure the dependency injection system to register the IEntityCache service in the ConfigureServices method of your module class:

context.Services.AddEntityCache<Product, Guid>();

Now you can inject the IEntityCache<Product, Guid> service wherever you need:

public class ProductAppService : ApplicationService, IProductAppService
{
    private readonly IEntityCache<Product, Guid> _productCache;

    public ProductAppService(IEntityCache<Product, Guid> productCache)
    {
        _productCache = productCache;
    }

    public async Task<ProductDto> GetAsync(Guid id)
    {
        var product = await _productCache.GetAsync(id);
        return ObjectMapper.Map<Product, ProductDto>(product);
    }
}

Note that we've used the ObjectMapper service to map from Product to ProductDto. You should configure that object mapping to make that example service properly work.

That's all. The cache name (in the distributed cache server) will be the full name (with namespace) of the Product class. You can use the [CacheName] attribute to change it. Please refer to the caching document for details.

Using a Cache Item Class

In the previous section, we've directly cached the Product entity. In that case, the Product class must be serializable to JSON (and deserializable from JSON). Sometimes that might not be possible or you may want to use another class to store the cache data. For example, we may want to use the ProductDto class instead of the Product class for the cached object of the Product entity.

Assume that we've created a ProductDto class as shown below:

public class ProductDto : EntityDto<Guid>
{
    public string Name { get; set; }
    public string Description { get; set; }
    public float Price { get; set; }
    public int StockCount { get; set; }
}

Now, we can register the entity cache services to dependency injection in the ConfigureServices method of your module class with three generic parameters, as shown below:

context.Services.AddEntityCache<Product, ProductDto, Guid>();

Since the entity cache system will perform the object mapping (from Product to ProductDto), we should configure the object map. Here, an example configuration with AutoMapper:

public class MyMapperProfile : Profile
{
    public MyMapperProfile()
    {
        CreateMap<Product, ProductDto>();
    }
}

Now, you can inject the IEntityCache<ProductDto, Guid> service wherever you want:

public class ProductAppService : ApplicationService, IProductAppService
{
    private readonly IEntityCache<ProductDto, Guid> _productCache;

    public ProductAppService(IEntityCache<ProductDto, Guid> productCache)
    {
        _productCache = productCache;
    }

    public async Task<ProductDto> GetAsync(Guid id)
    {
        return await _productCache.GetAsync(id);
    }
}

Notice that the _productCache.GetAsync method already returns a ProductDto object, so we could directly return it from our application service.

Configuration

All of the context.Services.AddEntityCache() methods get an optional DistributedCacheEntryOptions parameter where you can easily configure the caching options:

context.Services.AddEntityCache<Product, ProductDto, Guid>(
    new DistributedCacheEntryOptions
    {
        SlidingExpiration = TimeSpan.FromMinutes(30)
    }
);

The default cache duration is 2 minutes with the AbsoluteExpirationRelativeToNow configuration.

Additional Notes

  • Entity classes should be serializable/deserializable to/from JSON to be cached (because it's serialized to JSON when saving in the Distributed Cache). If your entity class is not serializable, you can consider using a cache-item/DTO class instead, as explained before.
  • Entity Caching System is designed as read-only. You should use the standard repository methods to manipulate the entity if you need to. If you need to manipulate (update) the entity, do not get it from the entity cache. Instead, read it from the repository, change it and update using the repository.

See Also

Contributors


Last updated: July 31, 2024 Edit this page on GitHub

Was this page helpful?

Please make a selection.

To help us improve, please share your reason for the negative feedback in the field below.

Please enter a note.

Thank you for your valuable feedback!

Please note that although we cannot respond to feedback, our team will use your comments to improve the experience.

In this document
Community Talks

Building Modular Monolith Applications Using .NET and ABP Framework

17 Oct, 17:00
Online
Watch the Event
Mastering ABP Framework Book
Mastering ABP Framework

This book will help you gain a complete understanding of the framework and modern web application development techniques.

Learn More