using System.Text.Json; using DAL.Database; using Domain.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; namespace DAL.Repositories; public class ProductRepository: IProductRepository { private readonly DatabaseContext _db; private readonly ILogger _logger; private readonly IDistributedCache _cache; public ProductRepository(DatabaseContext db, ILogger logger, IDistributedCache cache) { _db = db; _logger = logger; _cache = cache; } public async Task Get(int id, int cacheLifetime, CancellationToken token) { var productCache = await _cache.GetAsync(id.ToString(), token); var product = new Product(); if(productCache is not null) product = JsonSerializer.Deserialize(productCache); if (product is not null) return product; product = await _db.Products.FindAsync(id) ?? throw new KeyNotFoundException("Product not found"); _db.Entry(product).Reference(p => p.Description).Load(); await _cache.SetStringAsync( product.Id.ToString(), JsonSerializer.Serialize(product), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheLifetime) }, token); return product; } public async Task> GetAll(int cacheLifeTime, CancellationToken token) { var productsCache = await _cache.GetAsync("Products", token); var products = new List(); if (productsCache is not null) products = JsonSerializer.Deserialize> (productsCache); if(products is not null && products.Count() > 0) return products; products = await _db.Products .Include(p => p.Description) .ToListAsync(token) ?? throw new NullReferenceException("Database is empty"); await _cache.SetStringAsync("Products", JsonSerializer.Serialize(products), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheLifeTime) }, token); return products; } public async Task Delete(int id, CancellationToken token) { var product = await _db.Products.FindAsync(id) ?? throw new KeyNotFoundException("Product not found"); _db.Products.Remove(product); await _cache.RemoveAsync(id.ToString(), token); await _db.SaveChangesAsync(); } public async Task Update(Product entity, int cacheLifetime, CancellationToken token) { var product = await _db.Products.FindAsync(entity.Id) ?? throw new KeyNotFoundException("Product not found"); _db.Entry(product).Reference(p => p.Description).Load(); _db.Entry(product).CurrentValues.SetValues(entity); _db.Entry(product.Description).CurrentValues.SetValues(entity.Description); await _cache.RemoveAsync(product.Id.ToString(), token); await _cache.SetStringAsync(product.Id.ToString(), JsonSerializer.Serialize(entity), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheLifetime) }, token); await _db.SaveChangesAsync(); } public async Task Create(Product entity, int cacheLifeTime, CancellationToken token) { using (var transaction = _db.Database.BeginTransaction()) { try { await _db.Products.AddAsync(entity); await _db.Descriptions.AddAsync(entity.Description); await _db.SaveChangesAsync(); transaction.Commit(); var products = await _db.Products .Include(p => p.Description) .ToListAsync() ?? throw new NullReferenceException("Database is empty"); await _cache.RemoveAsync("Products", token); await _cache.SetStringAsync("Products", JsonSerializer.Serialize(products), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheLifeTime) }, token); } catch (Exception ex) { _logger.LogError(ex.Message); transaction.Rollback(); throw new Exception(ex.Message); } finally { transaction.Dispose(); } } } }