299 lines
11 KiB
C#
299 lines
11 KiB
C#
using Microsoft.Extensions.Caching.Distributed;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using Newtonsoft.Json;
|
|
using NKC.Data.DbModels;
|
|
using NKC.Data.DTO;
|
|
using NLog;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
|
|
namespace REMAN.Data
|
|
{
|
|
public class RDataService : IDisposable
|
|
{
|
|
#region Private Fields
|
|
|
|
private static IConfiguration _configuration = null!;
|
|
private static ILogger<RDataService> _logger = null!;
|
|
private static JsonSerializerSettings? JSSettings;
|
|
|
|
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
|
|
|
|
//private readonly IEmailSender _emailSender;
|
|
//private readonly UserManager<IdentityUser> _userManager;
|
|
private readonly IDistributedCache distributedCache;
|
|
|
|
private readonly IMemoryCache memoryCache;
|
|
private List<string> cachedDataList = new List<string>();
|
|
|
|
/// <summary>
|
|
/// Durata assoluta massima della cache IN SECONDI
|
|
/// </summary>
|
|
private int chAbsExp = 60 * 5;
|
|
|
|
/// <summary>
|
|
/// Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire rimossa
|
|
/// NON estende oltre il tempo massimo di validità della cache (chAbsExp)
|
|
/// </summary>
|
|
private int chSliExp = 60 * 1;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Protected Fields
|
|
|
|
protected const string rKeyMaterials = "Cache:Materials";
|
|
protected const string rKeyQrRemnants = "Cache:QrRemnants";
|
|
protected const string rKeyRemnants = "Cache:Remnants";
|
|
protected static string connStringBBM = "";
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Public Fields
|
|
|
|
public static NKC.Data.Controllers.NKCController dbController = null!;
|
|
|
|
#endregion Public Fields
|
|
|
|
#region Public Constructors
|
|
|
|
public RDataService(IConfiguration configuration, ILogger<RDataService> logger, IMemoryCache memoryCache, IDistributedCache distributedCache)
|
|
{
|
|
_logger = logger;
|
|
_configuration = configuration;
|
|
// conf cache
|
|
this.memoryCache = memoryCache;
|
|
this.distributedCache = distributedCache;
|
|
|
|
// json serializer...
|
|
// FIX errore loop circolare
|
|
// https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/
|
|
JSSettings = new JsonSerializerSettings()
|
|
{
|
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
|
};
|
|
// conf DB
|
|
string connStr = _configuration.GetConnectionString("NKC.DB");
|
|
if (string.IsNullOrEmpty(connStr))
|
|
{
|
|
_logger.LogError("ConnString empty!");
|
|
}
|
|
else
|
|
{
|
|
dbController = new NKC.Data.Controllers.NKCController(configuration);
|
|
}
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Private Methods
|
|
|
|
private DistributedCacheEntryOptions cacheOpt(bool fastCache)
|
|
{
|
|
var numSecAbsExp = fastCache ? chAbsExp : chAbsExp * 10;
|
|
var numSecSliExp = fastCache ? chSliExp : chSliExp * 10;
|
|
return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp));
|
|
}
|
|
|
|
#endregion Private Methods
|
|
|
|
#region Public Methods
|
|
|
|
public void Dispose()
|
|
{
|
|
// Clear database controller
|
|
dbController.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// invalida tutta la cache in caso di update
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task InvalidateAllCache()
|
|
{
|
|
await distributedCache.RemoveAsync(rKeyMaterials);
|
|
await distributedCache.RemoveAsync(rKeyRemnants);
|
|
foreach (var item in cachedDataList)
|
|
{
|
|
await distributedCache.RemoveAsync(item);
|
|
}
|
|
cachedDataList = new List<string>();
|
|
}
|
|
|
|
public async Task<List<MaterialDTO>> MaterialsGetAll()
|
|
{
|
|
List<MaterialDTO>? dbResult = new List<MaterialDTO>();
|
|
string rawData;
|
|
var redisDataList = await distributedCache.GetAsync(rKeyMaterials);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<MaterialDTO>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.MaterialsGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(rKeyMaterials, redisDataList, cacheOpt(false));
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"Effettuata lettura da DB + caching per GetMaterials: {ts.TotalMilliseconds} ms");
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<MaterialDTO>();
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<List<MovMagModel>> MovMagGetFilt(int RemnId, int numShow)
|
|
{
|
|
List<MovMagModel> dbResult = new List<MovMagModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
dbResult = dbController.MovMagGetFilt(RemnId, numShow);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"Effettuata lettura da DB + caching per MovMagGetFilt: {ts.TotalMilliseconds} ms");
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<bool> AddPrintJob(int RemnId)
|
|
{
|
|
bool answ = dbController.AddPrintJob("docRemnant", $"{RemnId}", "queueRemnants");
|
|
return await Task.FromResult(answ);
|
|
}
|
|
|
|
public async Task<List<RemnantsModel>> RemnantsGetFilt(int matId, int minQty)
|
|
{
|
|
List<RemnantsModel>? dbResult = new List<RemnantsModel>();
|
|
string rawData;
|
|
string cacheKey = $"{rKeyRemnants}:{matId}:{minQty}";
|
|
if (!cachedDataList.Contains(cacheKey))
|
|
{
|
|
cachedDataList.Add(cacheKey);
|
|
}
|
|
|
|
var redisDataList = await distributedCache.GetAsync(cacheKey);
|
|
if (redisDataList != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisDataList);
|
|
dbResult = JsonConvert.DeserializeObject<List<RemnantsModel>>(rawData);
|
|
}
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
var rawList = dbController.RemnantsGetFilt(matId, minQty);
|
|
dbResult = rawList.OrderBy(r => r.RemDtmx).ThenBy(o => o.Area).ToList();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
redisDataList = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(false));
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"Effettuata lettura da DB + caching per RemnantsGetAll: {ts.TotalMilliseconds} ms");
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<RemnantsModel>();
|
|
}
|
|
return await Task.FromResult(dbResult);
|
|
}
|
|
|
|
public async Task<bool> RemnantsIsDupl(RemnantsModel currItem)
|
|
{
|
|
bool answ = false;
|
|
var rawList = dbController.RemnantsGetFilt(currItem.MatID, 0);
|
|
var duplicati = rawList
|
|
.Where(x => x.RemnID != currItem.RemnID && x.LMm == currItem.LMm && x.WMm == currItem.WMm && x.TMm == currItem.TMm)
|
|
.ToList();
|
|
answ = duplicati.Count > 0;
|
|
return await Task.FromResult(answ);
|
|
}
|
|
|
|
public async Task<bool> RemnantsMovMag(RemnantsModel currItem, string userId, int deltaQty)
|
|
{
|
|
bool done = false;
|
|
try
|
|
{
|
|
// recupero item da DB
|
|
var currRecord = dbController.RemnantGetByid(currItem.RemnID);
|
|
if (currRecord != null && currRecord.RemnID == currItem.RemnID)
|
|
{
|
|
// modifico qty entro limiti >=0..
|
|
if (currRecord.QtyAvail + deltaQty >= 0)
|
|
{
|
|
currRecord.QtyAvail = currRecord.QtyAvail + deltaQty;
|
|
done = dbController.RemnantsUpsert(currRecord, userId);
|
|
await InvalidateAllCache();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in RemnantsMovMag:{Environment.NewLine}{exc}");
|
|
}
|
|
return await Task.FromResult(done);
|
|
}
|
|
|
|
public async Task<bool> RemnantsUpsert(RemnantsModel currItem, string userId)
|
|
{
|
|
bool done = false;
|
|
try
|
|
{
|
|
done = dbController.RemnantsUpsert(currItem, userId);
|
|
await InvalidateAllCache();
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in RemnantsUpsert:{Environment.NewLine}{exc}");
|
|
}
|
|
return await Task.FromResult(done);
|
|
}
|
|
|
|
public void rollBackEdit(object item)
|
|
{
|
|
dbController.rollBackEntity(item);
|
|
}
|
|
|
|
public async Task<RemnantsModel> SearchQrRemnant(string QrCode)
|
|
{
|
|
RemnantsModel? answ = new RemnantsModel();
|
|
string rawData = "";
|
|
string cacheKey = $"{rKeyQrRemnants}:{QrCode}";
|
|
// cerco in redis
|
|
var redisData = await distributedCache.GetAsync(cacheKey);
|
|
if (redisData != null)
|
|
{
|
|
rawData = Encoding.UTF8.GetString(redisData);
|
|
answ = JsonConvert.DeserializeObject<RemnantsModel>(rawData);
|
|
}
|
|
// se non trovo cerco su DB
|
|
else
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
var foundItem = dbController.RemnantGetByQr(QrCode);
|
|
if (foundItem != null && foundItem.RemDtmx == QrCode)
|
|
{
|
|
rawData = JsonConvert.SerializeObject(foundItem, JSSettings);
|
|
redisData = Encoding.UTF8.GetBytes(rawData);
|
|
await distributedCache.SetAsync(cacheKey, redisData, cacheOpt(false));
|
|
answ = foundItem;
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"Effettuata lettura da DB + caching per SearchQrRemnant: {ts.TotalMilliseconds} ms");
|
|
}
|
|
if (answ == null)
|
|
{
|
|
answ = new RemnantsModel();
|
|
}
|
|
return await Task.FromResult(answ);
|
|
}
|
|
|
|
#endregion Public Methods
|
|
}
|
|
} |