I'm building a webshop using ASP.Net Core
(Razor Pages) with EF Core
. To speed up a lot of calculation, I cache all the products (~100.000). The information is coming from our db.
Models
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.
The caching method
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. 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.
Solutions - tried but not satisfying
Method 1
I can set caching of the whole list to 15 minutes, that will work, but it's not what I want. Refreshing the whole cache is slow and not necessary. 99.9% of the data has not changed.
Method 2
Inside my model ProductInformation I make a method that updates the Product:
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()
. 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). 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. Everywhere I display a ProdctInformation, I need to call something like _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? I think its not the way to go.
Question
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). How can we handle this?