[英]ASP.NET Core - Update 1 Element of a cached List<Element> in IMemoryCache using EF Core
I'm building a webshop using ASP.Net Core
(Razor Pages) with EF Core
.我正在使用
ASP.Net Core
(Razor Pages) 和EF Core
构建一个网上商店。 To speed up a lot of calculation, I cache all the products (~100.000).为了加快大量计算,我缓存了所有产品(~100.000)。 The information is coming from our db.
信息来自我们的数据库。
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...
}
In my DBContext I define that every PoductInformation has exact one Product.在我的 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;
});
}
The whole caching method takes 100-120 seconds.整个缓存方法需要 100-120 秒。 Now another system updates my price in the DB for one product and of course I want to show the correct price of that product on my webshop.
现在另一个系统更新了我在数据库中的一种产品价格,当然我想在我的网上商店中显示该产品的正确价格。 Let's assume I want to check the price every 15 minutes.
假设我想每 15 分钟检查一次价格。
Method 1方法一
I can set caching of the whole list to 15 minutes, that will work, but it's not what I want.我可以将整个列表的缓存设置为 15 分钟,这会起作用,但这不是我想要的。 Refreshing the whole cache is slow and not necessary.
刷新整个缓存很慢而且没有必要。 99.9% of the data has not changed.
99.9% 的数据没有改变。
Method 2方法二
Inside my model ProductInformation I make a method that updates the Product:在我的 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
}
}
Everywhere I display a ProductInformation, I call UpdateProduct()
.在我显示 ProductInformation 的任何地方,我都会调用
UpdateProduct()
。 Then I only re-check the 'old' prices from products that I display.然后我只重新检查我展示的产品的“旧”价格。 This is much more efficiënt than recalculate the whole cache.
这比重新计算整个缓存要有效得多。 But now I need a DB connection inside my ProductInformation (that is cached).
但现在我需要在我的 ProductInformation 中建立一个数据库连接(即缓存)。 I can't get this to work.
我不能让它工作。
Method 3方法三
Since the problem in method 2 is that I don't have a DB connection, I can take the UpdateProduct()
method outside the model and put it in my repository where I have a DB connection.由于方法 2 中的问题是我没有数据库连接,因此我可以在 model 之外采用
UpdateProduct()
方法并将其放入我有数据库连接的存储库中。 Everywhere I display a ProdctInformation, I need to call something like _proudctRepository.UpdateProduct(ref ProductInformation);
在我显示 ProdctInformation 的任何地方,我都需要调用类似
_proudctRepository.UpdateProduct(ref ProductInformation);
. . This method looks like:
这个方法看起来像:
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()
}
But this feels not right.但这感觉不对。 The Entity Framework has organized for me the connection between ProductInformation and Product, is it then possible to redefine Product this way?
实体框架为我组织了 ProductInformation 和 Product 之间的连接,那么是否可以通过这种方式重新定义 Product? I think its not the way to go.
我认为这不是通往 go 的方式。
I think a lot of people use IMemoryCaching for equal situations (where you want to update just a single element in a cached List or just some elements (price / stock /...) of a cached list element).我认为很多人在相同的情况下使用 IMemoryCaching(您只想更新缓存列表中的单个元素或缓存列表元素的某些元素(价格/股票/...))。 How can we handle this?
我们该如何处理呢?
1) Add LastChanged
(datetime[offset]) column to your Product
database and ask "another system" update it too when it updates your price. 1) 将
LastChanged
(datetime[offset]) 列添加到您的Product
数据库中,并在更新您的价格时询问“另一个系统”是否也更新它。 With this, you can easily save Max(LastChanged)
in your cache and query only for changed Products, reducing time and size of updates, and you can do it more frequently.这样,您可以轻松地将
Max(LastChanged)
保存在缓存中并仅查询更改的产品,从而减少更新时间和大小,并且可以更频繁地执行此操作。
2) Add AsNoTracking when putting data into cache. 2)将数据放入缓存时添加AsNoTracking 。 You will not update them back to DB (I guess), so no-tracking will speed up everything a little.
您不会将它们更新回数据库(我猜),因此不跟踪会稍微加快一切。 Also, this will give you no-worry about
ProductInformation
- Product
EF relations, because EF will not be tracking them anyway and pi.Product
will be a usual object-holding property without any hidden magic.此外,这将使您不必担心
ProductInformation
- Product
EF 关系,因为 EF 无论如何都不会跟踪它们,并且pi.Product
将是一个通常的对象持有属性,没有任何隐藏的魔法。
3) It's not good to check for price updates on every page render. 3) 在每个页面渲染时检查价格更新是不好的。 Updates should run in other thread / background.
更新应该在其他线程/后台运行。 Setup some background task that will check for updated prices and reload updated objects into cache - with (1) you can run updates every 5 minutes or less.
设置一些后台任务来检查更新的价格并将更新的对象重新加载到缓存中 - 使用 (1) 您可以每 5 分钟或更短时间运行一次更新。 Check here DbContext for background tasks via Dependency Injection for obtaining DbContext.
通过依赖注入查看后台任务的 DbContext以获取 DbContext。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.