实体缓存
ABP提供了一个基于分布式缓存系统之上的实体缓存系统。它为您执行以下操作:
- 在首次调用时从数据库获取实体(通过使用仓储),然后在后续调用中从缓存中获取。
- 如果实体被更新或删除,自动使缓存的实体失效。因此,在下次调用时会从数据库中重新获取并重新缓存。
缓存实体对象
IEntityCache<TEntityCacheItem, TKey>是ABP提供的一个简单服务,用于缓存实体。假设您有一个如下所示的Product实体:
public class Product : AggregateRoot<Guid>
{
public Product(Guid id)
{
Id = id;
}
public string Name { get; set; }
public string Description { get; set; }
public float Price { get; set; }
public int StockCount { get; set; }
}
如果您想缓存此实体,您应首先配置依赖注入系统,在您的模块类的ConfigureServices方法中注册IEntityCache服务:
context.Services.AddEntityCache<Product, Guid>();
现在您可以在任何需要的地方注入IEntityCache<Product, Guid>服务:
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);
}
}
注意,我们使用了
ObjectMapper服务将Product映射到ProductDto。您应配置该对象映射以使该示例服务正常工作。
就这样。缓存名称(在分布式缓存服务器中)将是Product类的全名(包括命名空间)。您可以使用[CacheName]属性来更改它。详情请参阅缓存文档。
使用缓存项类
在上一节中,我们直接缓存了Product实体。在这种情况下,Product类必须可序列化为JSON(并且可从JSON反序列化)。有时这可能无法实现,或者您可能希望使用另一个类来存储缓存数据。例如,我们可能希望使用ProductDto类而不是Product类作为Product实体的缓存对象。
假设我们创建了一个如下所示的ProductDto类:
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; }
}
现在,我们可以使用三个泛型参数,在您的模块类的ConfigureServices方法中向依赖注入注册实体缓存服务,如下所示:
context.Services.AddEntityCache<Product, ProductDto, Guid>();
由于实体缓存系统将执行对象映射(从Product到ProductDto),我们应配置对象映射。这里是一个使用AutoMapper的示例配置:
public class MyMapperProfile : Profile
{
public MyMapperProfile()
{
CreateMap<Product, ProductDto>();
}
}
如果您使用Mapperly,您可以创建一个新的映射类,实现带有[Mapper]属性的MapperBase<Product, ProductDto>类,如下所示:
[Mapper]
public partial class ProductToProductDtoMapper : MapperBase<Product, ProductDto>
{
public override partial ProductDto Map(Product source);
public override partial void Map(Product source, ProductDto destination);
}
现在,您可以在任何需要的地方注入IEntityCache<ProductDto, Guid>服务:
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);
}
}
请注意,_productCache.GetAsync方法已经返回一个ProductDto对象,因此我们可以直接从应用服务中返回它。
配置
所有的context.Services.AddEntityCache()方法都接受一个可选的DistributedCacheEntryOptions参数,您可以在其中轻松配置缓存选项:
context.Services.AddEntityCache<Product, ProductDto, Guid>(
new DistributedCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(30)
}
);
默认缓存持续时间为2分钟,使用
AbsoluteExpirationRelativeToNow配置。
附加说明
- 实体类必须可序列化/可从JSON反序列化才能被缓存(因为在保存到分布式缓存时会被序列化为JSON)。如果您的实体类不可序列化,您可以考虑使用缓存项/DTO类,如前所述。
- 实体缓存系统设计为只读。如果您需要操作实体,应使用标准的仓储方法。如果需要操作(更新)实体,不要从实体缓存中获取它。而是从仓储中读取,更改它并使用仓储进行更新。
抠丁客


