如何在C#中缓存具有多个键的对象

Gur*_*ler 5 c# caching memorycache .net-core asp.net-core

我有2个或更多属性唯一的模型。例如,该类的对象在Entity名称和ID上都是唯一的。

public class Entity
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我有一个模型存储库:

public class EntityRepository
{
    ...
    public Entity GetById(int id)
    {
        return db.GetById(id);
    }
    public Entity GetByName(string name)
    {
        return db.GetByName(name);
    }
}
Run Code Online (Sandbox Code Playgroud)

什么是缓存到两个呼叫的最佳方式GetById,并呼吁GetByName使用Microsoft.Extensions.Caching.Memory.IMemoryCache

当前解决方案:

public class EntityRepository
{
    ...
    public Entity GetById(int id)
    {
        return Cache.GetOrCreate($"id:{id}", cacheEntry =>
        {
            return db.GetById(id);
        });
    }
    public Entity GetByName(string name)
    {
        return Cache.GetOrCreate($"name:{name}", cacheEntry =>
        {
            return db.GetByName(name);
        });
    }
    public void RemoveById(int id)
    {
        db.RemoveById(id);
        Cache.Remove($"id:{id}");
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是,如果我通过ID删除实体,则可以通过ID将其从缓存中删除,但是其他键仍然存在。并且更新实体存在类似的问题。

有没有比在缓存中两次保存对象更好的解决方案?

Ath*_*ras 0

在您的情况下,我会以不同的方式进行缓存,基本上,我会将缓存的条目保留在缓存中的列表中,然后检索该列表并在那里进行搜索。

如果您认为列表太大而无法搜索,那么出于性能原因您可能需要进行一些分区。

一个一般的例子如下。

public class EntityRepository
{

    public Entity GetById(int id)
    {
        List<Entity> entities = Cache.GetOrCreate($"entities", cacheEntry =>
        {
            // Create an empty list of entities
            return new List<Entity>();
        });

        // Look for the entity
        var entity = entities.Where(e => e.id == id).FirstOrDefault();
        // if not there, then add it to the cached list
        if (entity == null)
        {
            entity = db.GetById(id);
            entities.Add(entity)
            // Update the cache
            Cache.Set($"entities", entities);
        }
        return entity;
    }
    public Entity GetByName(string name)
    {
        // Same thing with id    
    }
    public void RemoveById(int id)
    {
        // load the list, remove item and update cache
    }
}
Run Code Online (Sandbox Code Playgroud)

在任何其他情况下,您都需要使用某种逻辑来包装您的实现。也许是多键字典,或者某种数据结构来保留历史记录并进行自定义清理。但没有任何开箱即用的东西。

您还可以通过将实体列表提取到 getter 和 setter 中来简化代码和重复,如下所示:

public List<Entity> Entities
{
    get { return Cache.GetOrCreate($"entities", cacheEntry =>
                 {
                     // Create an empty list of entities
                     return new List<Entity>();
                 }); 
    }
    set { Cache.Set($"entities", value); }
}
Run Code Online (Sandbox Code Playgroud)