C# 在实体发生更改后更新IMemoryCache

C# 在实体发生更改后更新IMemoryCache,c#,entity-framework,caching,asp.net-core,asp.net-core-mvc,C#,Entity Framework,Caching,Asp.net Core,Asp.net Core Mvc,我有一个CacheService,它使用GetOrCreateAync基于密钥创建缓存。我正在缓存照片实体,该实体具有byte[]属性。 此缓存很好,并按预期进行检索。但是,如果照片实体已更新,缓存仍会像您预期的那样保留旧实体,因为它尚未过期,如何在保存此实体时强制更新缓存?我是否删除现有的缓存实体并重新添加更新的实体 我的CacheService中的FromCacheSync方法示例 当实体更改时,您需要使缓存密钥无效 如果直接在DbContext上操作,这可能有点棘手。但由于您使用的是存储库

我有一个CacheService,它使用GetOrCreateAync基于密钥创建缓存。我正在缓存照片实体,该实体具有byte[]属性。 此缓存很好,并按预期进行检索。但是,如果照片实体已更新,缓存仍会像您预期的那样保留旧实体,因为它尚未过期,如何在保存此实体时强制更新缓存?我是否删除现有的缓存实体并重新添加更新的实体

我的CacheService中的FromCacheSync方法示例


当实体更改时,您需要使缓存密钥无效

如果直接在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));
    }
}
与装饰图案一起使用 问题是,内置的DI/IoC容器不支持decorator注册,因此您必须通过factory模式自己制作,或者使用支持它的第三方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容器的composition根目录中使用new本身并不坏,但使用第三方IoC容器更方便


当然,您也可以在IoC容器中注册PhotographRespository并将其解析。但是,这也允许您将PhotographRespository注入到服务中,而上述方法阻止了这一点,因为只有iPhotographRespository接口被注册。

当实体更改时,您需要使缓存密钥无效

如果直接在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));
    }
}
与装饰图案一起使用 问题是,内置的DI/IoC容器不支持decorator注册,因此您必须通过factory模式自己制作,或者使用支持它的第三方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容器的composition根目录中使用new本身并不坏,但使用第三方IoC容器更方便


当然,您也可以在IoC容器中注册PhotographRespository并将其解析。但这也允许您将PhotographRespository注入到您的服务中,而上述情况阻止了这一点,因为只注册了iPhotographRespository接口。

谢谢,这是我的想法,但我不太确定在我的存储库模式中使用IMemoryCache是否是一种好的做法,但是把它放在这里是很有意义的,没错。但是为了简单地展示如何做,这已经足够好了。实际上,您可能希望使用并创建一个PhotographRespository和一个CachedPhotographRepository,用于注入iPhotographRespository或PhotographRespository并包装调用。只是忙着写那个大答案。这很有意义,提供的答案在我的场景中不起作用,因为我正在使用通用存储库来更新实体,所以很遗憾无法将其封装在缓存中,但答案本身非常有用,谢谢,当您有空时,是否可以向我展示您上面的意思,因为这是我以前在通用存储库中没有做过的事情。除非我在我的照片存储库中创建了一个新的更新方法,该方法不使用从我的通用存储库继承的方法,但这并不理想,将来可能会令人困惑?谢谢还添加了decorator模式,但请记住,它不是原始问题的一部分,下次可能更适合新问题。谢谢,这是我一直在想的,但我不太确定在我的存储库模式周围使用IMemoryCache是否是一个好的实践,但在这里使用它确实非常有意义。这是正确的。但是为了简单地展示如何做,这已经足够好了。实际上,您可能希望使用并创建一个PhotographRespository和一个CachedPhotographRepository,用于注入iPhotographRespository或PhotographRespository并包装调用。只是忙着写那个大答案。这很有意义,提供的答案在我的场景中不起作用,因为我正在使用通用存储库来更新实体,所以很遗憾无法将其封装在缓存中,但答案本身非常有用,谢谢,当您有空时,是否可以向我展示您上面的意思,因为这是我以前在通用存储库中没有做过的事情。除非我在我的照片存储库中创建了一个新的更新方法,该方法不使用从我的通用存储库继承的方法,但这并不理想,将来可能会令人困惑?谢谢还添加了装饰图案,但请记住,这不是原始问题的一部分,下次可能更适合新问题。请解释投票失败的原因 请解释投票被否决的原因。
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>()
    )
);