繁体   English   中英

ASP.NET 内核 - 更新缓存列表的 1 个元素<element>在 IMemoryCache 中使用 EF Core</element>

[英]ASP.NET Core - Update 1 Element of a cached List<Element> in IMemoryCache using EF Core

我正在使用ASP.Net Core (Razor Pages) 和EF Core构建一个网上商店。 为了加快大量计算,我缓存了所有产品(~100.000)。 信息来自我们的数据库。

楷模

class ProductInformation{
    // some information about how to display a product
    public string productnumber {get; set;}
    public Product product {get; set;}
}

class Product{
    public string productnumber {get; set;}
    public decimal price {get; set;}
    public Category category {get; set}
    // and a lot more...
}

在我的 DBContext 中,我定义每个 PoductInformation都有一个确切的产品。

缓存方法

private readonly IMemoryCache _cache; // is set in the constructor
private readonly DBContext _dbContext; // is set in the constructor
public List<ProductInformation> GetProductInformationList(){
    List<ProductInformation> = _cache.GetOrCreate("ProductInformations", entry =>
    {
        entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24);
        List<ProductInformation> list =_dbContext.ProductInformation.ToList();
        // do a lot of calculations on the list-elements
        return list;
    });
}

整个缓存方法需要 100-120 秒。 现在另一个系统更新了我在数据库中的一种产品价格,当然我想在我的网上商店中显示该产品的正确价格。 假设我想每 15 分钟检查一次价格。

解决方案 - 尝试但不满意

方法一

我可以将整个列表的缓存设置为 15 分钟,这会起作用,但这不是我想要的。 刷新整个缓存很慢而且没有必要。 99.9% 的数据没有改变。

方法二

在我的 model ProductInformation 中,我创建了一个更新产品的方法:

class ProductInformation{
    // some information about how to display a product
    public string productnumber {get; set;}
    public Product product {get; set;}

    pubic DateTime ProductTimeStamp {get; set;}
    public UpdateProduct(){
        // If ProductTimeStamp is more than 15 minutes in the past
        // get Product from the DB
        // and update the timestamp
    }
}

在我显示 ProductInformation 的任何地方,我都会调用UpdateProduct() 然后我只重新检查我展示的产品的“旧”价格。 这比重新计算整个缓存要有效得多。 但现在我需要在我的 ProductInformation 中建立一个数据库连接(即缓存)。 我不能让它工作。

方法三

由于方法 2 中的问题是我没有数据库连接,因此我可以在 model 之外采用UpdateProduct()方法并将其放入我有数据库连接的存储库中。 在我显示 ProdctInformation 的任何地方,我都需要调用类似_proudctRepository.UpdateProduct(ref ProductInformation); . 这个方法看起来像:

public void UpdateProduct(ref ProductInformation pi){
    pi.Product = _dbContext.Product.Where(p => p.productnumber == pi.productnumber);
   // Of course I also need to do the calculations from the caching-method in GetProductInformationList()
}

但这感觉不对。 实体框架为我组织了 ProductInformation 和 Product 之间的连接,那么是否可以通过这种方式重新定义 Product? 我认为这不是通往 go 的方式。

问题

我认为很多人在相同的情况下使用 IMemoryCaching(您只想更新缓存列表中的单个元素或缓存列表元素的某些元素(价格/股票/...))。 我们该如何处理呢?

1) 将LastChanged (datetime[offset]) 列添加到您的Product数据库中,并在更新您的价格时询问“另一个系统”是否也更新它。 这样,您可以轻松地将Max(LastChanged)保存在缓存中并仅查询更改的产品,从而减少更新时间和大小,并且可以更频繁地执行此操作。

2)将数据放入缓存时添加AsNoTracking 您不会将它们更新回数据库(我猜),因此不跟踪会稍微加快一切。 此外,这将使您不必担心ProductInformation - Product EF 关系,因为 EF 无论如何都不会跟踪它们,并且pi.Product将是一个通常的对象持有属性,没有任何隐藏的魔法。

3) 在每个页面渲染时检查价格更新是不好的。 更新应该在其他线程/后台运行。 设置一些后台任务来检查更新的价格并将更新的对象重新加载到缓存中 - 使用 (1) 您可以每 5 分钟或更短时间运行一次更新。 通过依赖注入查看后台任务的 DbContext以获取 DbContext。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM