我有CacheService
使用GetOrCreateAsync
根据密钥创建缓存。我正在缓存一个具有byte[]
属性的照片实体。
这个缓存很好,并按预期检索。但是,如果照片实体更新,缓存仍然保留旧实体,因为它没有过期,如何在保存此实体时强制更新缓存?我是否删除现有的缓存实体并重新添加更新的实体?
我的FromCacheAsync
CacheService
方法示例
public async Task<T> FromCacheAsync<T>(string entityName, int clientId, Func<Task<T>> function)
{
string cacheKey = GetClientCacheKey(entityName, clientId, function);
if (!_cache.TryGetValue(cacheKey, out T entry))
{
async Task<T> factory(ICacheEntry cacheEntry)
{
return await function();
}
return await _cache.GetOrCreateAsync(cacheKey, factory);
}
return entry;
}
这是使用缓存的一个示例。
var existingPhotograph = await _cacheService.FromCacheAsync(nameof(_context.Photograph), clientId, async () =>
await _photographRepository.GetByStaffIdAsync(staff.StaffId));
答案 0 :(得分:1)
当实体更改时,您需要使缓存键无效。
如果直接操作DbContext,这可能有点棘手。但由于您使用的是存储库模式,因此更容易实现。
归结为将IMemoryCache
注入您的存储库并在图片更新时使其无效。
public class PhotographRepository : IPhotograpRepository
{
private readonly IMemoryCache _cache;
public PhotographReposiory(IMemoryCache cache, ...)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
}
public async Task Update(PhotographEntity entity)
{
// update your entity here
await _context.SaveChangesAsync();
// this invalidates your memory cache. Next call to _cache.TryGetValue
// results in a cache miss and the new entity is fetched from the database
_cache.Remove(GetClientCacheKey(entityName, clientId));
}
}
public class PhotographRepository : IPhotograpRepository
{
private readonly ApplicationDbContext _context;
public PhotographReposiory(ApplicationDbContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public async Task Update(PhotographEntity entity)
{
// update your entity here
await _context.SaveChangesAsync();
}
}
public class CachedPhotographRepository : IPhotograpRepository
{
private readonly IMemoryCache _cache;
private readonly IPhotograpRepository _repository;
public CachedPhotographRepository(IPhotograpRepository repository, IMemoryCache cache)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_repository = _repository ?? throw new ArgumentNullException(nameof(repository));
}
public async Task Update(PhotographEntity entity)
{
// do the update in the passed in repository
await _repository.Update(entity);
// if no exception is thrown, it was successful
_cache.Remove(GetClientCacheKey(entityName, clientId));
}
}
问题是,内置的DI / IoC容器不支持装饰器注册,因此您必须通过工厂模式自己制作或使用支持它的第三方IoC容器。
services.AddScoped<IPhotograpRepository>(provider =>
// Create an instance of PhotographRepository and inject the memory cache
new CachedPhotographRepository(
// create an instance of the repository and resolve the DbContext and pass to it
new PhotographRepository(provider.GetRequiredService<ApplicationDbContext>()),
provider.GetRequiredService<IMemoryCache>()
)
);
在组合根(配置DI / IoC容器)中使用new本身并不“坏”,但使用第三方IoC容器更方便。
当然,您也可以在IoC容器中注册PhotographRepository
并解决它。但是这也可以让你将PhotographRepository
注入到你的服务中,而上面会阻止它,因为只注册了IPhotographRepository
接口。