From 0c645ed96076102036632c7d2ac93688fd0af40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A4=D1=80=D0=BE=D0=BB=D0=BE=D0=B2?= Date: Fri, 16 Jul 2021 09:15:10 +0500 Subject: [PATCH] fix dictionaries sync --- AsbCloudInfrastructure/DependencyInjection.cs | 2 +- .../Services/AnalyticsService.cs | 2 +- .../Services/Cache/CacheTable.cs | 383 ++++-------------- .../Services/EventService.cs | 32 +- .../Services/TelemetryUserService.cs | 42 +- ConsoleApp1/Program.cs | 51 ++- 6 files changed, 155 insertions(+), 357 deletions(-) diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 488b0f10..3095e222 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -15,7 +15,7 @@ namespace AsbCloudInfrastructure public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration) { services.AddDbContext(options => - options.UseNpgsql(configuration.GetConnectionString("DefaultConnection"))); + options.UseNpgsql(configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Scoped); services.AddScoped(provider => provider.GetService()); diff --git a/AsbCloudInfrastructure/Services/AnalyticsService.cs b/AsbCloudInfrastructure/Services/AnalyticsService.cs index ed8e4233..986df4fc 100644 --- a/AsbCloudInfrastructure/Services/AnalyticsService.cs +++ b/AsbCloudInfrastructure/Services/AnalyticsService.cs @@ -275,7 +275,7 @@ namespace AsbCloudInfrastructure.Services return drillingAnalysis; } - private static double GetAForLinearFormula(IEnumerable<(double?, double)> rawData) + private static double GetAForLinearFormula(IEnumerable<(double? x, double y)> rawData) { var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData); diff --git a/AsbCloudInfrastructure/Services/Cache/CacheTable.cs b/AsbCloudInfrastructure/Services/Cache/CacheTable.cs index 7fbe6666..a0c37248 100644 --- a/AsbCloudInfrastructure/Services/Cache/CacheTable.cs +++ b/AsbCloudInfrastructure/Services/Cache/CacheTable.cs @@ -12,7 +12,6 @@ namespace AsbCloudInfrastructure.Services.Cache private readonly DbContext context; private (DateTime refreshDate, IEnumerable entities) data; private readonly List cached; - private readonly ReaderWriterLockSlim cacheLocker = new ReaderWriterLockSlim(); internal CacheTable(DbContext context, (DateTime refreshDate, IEnumerable entities) data) { @@ -25,36 +24,20 @@ namespace AsbCloudInfrastructure.Services.Cache public int Refresh() { - cacheLocker.EnterWriteLock(); - try - { - cached.Clear(); - var dbEntities = context.Set().ToList(); - cached.AddRange(dbEntities); - data.refreshDate = DateTime.Now; - return cached.Count; - } - finally - { - cacheLocker.ExitWriteLock(); - } + cached.Clear(); + var dbEntities = context.Set().ToList(); + cached.AddRange(dbEntities); + data.refreshDate = DateTime.Now; + return cached.Count; } public async Task RefreshAsync(CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - try - { - cached.Clear(); - var dbEntities = await context.Set().ToListAsync(token).ConfigureAwait(false); - cached.AddRange(dbEntities); - data.refreshDate = DateTime.Now; - return cached.Count; - } - finally - { - cacheLocker.ExitWriteLock(); - } + cached.Clear(); + var dbEntities = await context.Set().ToListAsync(token).ConfigureAwait(false); + cached.AddRange(dbEntities); + data.refreshDate = DateTime.Now; + return cached.Count; } private bool CheckRefresh(RefreshMode refreshMode) @@ -106,30 +89,24 @@ namespace AsbCloudInfrastructure.Services.Cache public TEntity FirstOrDefault(RefreshMode refreshMode = RefreshMode.IfResultEmpty) { bool isUpdated = CheckRefresh(refreshMode); - var result = cached.FirstOrDefault(); - if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { Refresh(); return cached.FirstOrDefault(); } - return result; } public async Task FirstOrDefaultAsync(RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) { bool isUpdated = await CheckRefreshAsync(refreshMode, token); - var result = cached.FirstOrDefault(); - if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { await RefreshAsync(token); return cached.FirstOrDefault(); } - return result; } @@ -139,30 +116,24 @@ namespace AsbCloudInfrastructure.Services.Cache public TEntity FirstOrDefault(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty) { bool isUpdated = CheckRefresh(refreshMode); - var result = cached.FirstOrDefault(predicate); - if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { Refresh(); return cached.FirstOrDefault(predicate); } - return result; } public async Task FirstOrDefaultAsync(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) { bool isUpdated = await CheckRefreshAsync(refreshMode, token); - var result = cached.FirstOrDefault(predicate); - if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { await RefreshAsync(token); return cached.FirstOrDefault(predicate); } - return result; } @@ -172,329 +143,153 @@ namespace AsbCloudInfrastructure.Services.Cache public IEnumerable Select(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty) { bool isUpdated = CheckRefresh(refreshMode); - var result = cached.Where(predicate); - if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { Refresh(); return cached.Where(predicate); } - return result; } public async Task> SelectAsync(Func predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default) { bool isUpdated = await CheckRefreshAsync(refreshMode, token); - var result = cached.Where(predicate); - if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated) { await RefreshAsync(token); return cached.Where(predicate); } - return result; } - public IEnumerable Update(Func predicate, Action mutation) + public IEnumerable Mutate(Func predicate, Action mutation) { - cacheLocker.EnterWriteLock(); - - try + var dbSet = context.Set(); + var dbEntities = dbSet.Where(predicate); + if (dbEntities.Any()) { - var dbSet = context.Set(); - var dbEntities = dbSet.Where(predicate); - if (dbEntities.Any()) - { - foreach (var dbEntity in dbEntities) - mutation(dbEntity); - context.SaveChanges(); - } - cached.RemoveAll(e => predicate(e)); - cached.AddRange(dbEntities); - return dbEntities; - } - finally - { - cacheLocker.ExitWriteLock(); + foreach (var dbEntity in dbEntities) + mutation(dbEntity); + context.SaveChanges(); } + cached.RemoveAll(e => predicate(e)); + cached.AddRange(dbEntities); + return dbEntities; } - public async Task> UpdateAsync(Func predicate, Action mutation, CancellationToken token = default) + public async Task> MutateAsync(Func predicate, Action mutation, CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - - try + var dbSet = context.Set(); + var dbEntities = dbSet.Where(predicate); + if (dbEntities.Any()) { - var dbSet = context.Set(); - var dbEntities = dbSet.Where(predicate); - if (dbEntities.Any()) - { - foreach (var dbEntity in dbEntities) - mutation(dbEntity); - await context.SaveChangesAsync(token).ConfigureAwait(false); - } - cached.RemoveAll(e => predicate(e)); - cached.AddRange(dbEntities); - return dbEntities; - } - finally - { - cacheLocker.ExitWriteLock(); + foreach (var dbEntity in dbEntities) + mutation(dbEntity); + await context.SaveChangesAsync(token).ConfigureAwait(false); } + cached.RemoveAll(e => predicate(e)); + cached.AddRange(dbEntities); + return dbEntities; } public TEntity Upsert(TEntity entity) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entityEntry; - if (cached.Contains(entity)) - { - entityEntry = dbSet.Update(entity); - cached.Remove(entity); - } - else - { - entityEntry = dbSet.Add(entity); - } - - context.SaveChanges(); - - cached.Add(entityEntry.Entity); - - return entityEntry.Entity; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var updated = dbSet.Update(entity); + context.SaveChanges(); + Refresh(); + return updated.Entity; } - - public async Task UpsertAsync(TEntity entity, CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entityEntry; - - if (cached.Contains(entity)) - { - entityEntry = dbSet.Update(entity); - cached.Remove(entity); - } - else - { - entityEntry = dbSet.Add(entity); - } - - await context.SaveChangesAsync(token).ConfigureAwait(false); - - cached.Add(entityEntry.Entity); - - return entityEntry.Entity; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var updated = dbSet.Update(entity); + await context.SaveChangesAsync(token).ConfigureAwait(false); + await RefreshAsync(token).ConfigureAwait(false); + return updated.Entity; } public IEnumerable Upsert(IEnumerable entities) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - - var upsertedEntries = new List>(entities.Count()); - foreach (var entity in entities) - { - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entityEntry; - if (cached.Contains(entity)) - { - entityEntry = dbSet.Update(entity); - cached.Remove(entity); - } - else - { - entityEntry = dbSet.Add(entity); - } - upsertedEntries.Add(entityEntry); - } - - context.SaveChanges(); - - var upserted = upsertedEntries.Select(e => e.Entity); - - cached.AddRange(upserted); - - return upserted; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var upsertedEntries = new List(entities.Count()); + foreach (var entity in entities) + upsertedEntries.Add(dbSet.Update(entity).Entity); + context.SaveChanges(); + Refresh(); + return upsertedEntries; } public async Task> UpsertAsync(IEnumerable entities, CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - - var upsertedEntries = new List>(entities.Count()); - foreach (var entity in entities) - { - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry entityEntry; - if (cached.Contains(entity)) - { - entityEntry = dbSet.Update(entity); - cached.Remove(entity); - } - else - { - entityEntry = dbSet.Add(entity); - } - upsertedEntries.Add(entityEntry); - } - - await context.SaveChangesAsync(token).ConfigureAwait(false); - - var upserted = upsertedEntries.Select(e => e.Entity); - - cached.AddRange(upserted); - - return upserted; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var upsertedEntries = new List(entities.Count()); + foreach (var entity in entities) + upsertedEntries.Add(dbSet.Update(entity).Entity); + await context.SaveChangesAsync(token).ConfigureAwait(false); + await RefreshAsync(token).ConfigureAwait(false); + return upsertedEntries; } + public void Remove(Func predicate) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - cached.RemoveAll(e => predicate(e)); - dbSet.RemoveRange(dbSet.Where(predicate)); - context.SaveChanges(); - return; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + cached.RemoveAll(e => predicate(e)); + dbSet.RemoveRange(dbSet.Where(predicate)); + context.SaveChanges(); + return; } public async Task RemoveAsync(Func predicate, CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - cached.RemoveAll(e => predicate(e)); - dbSet.RemoveRange(dbSet.Where(predicate)); - await context.SaveChangesAsync(token).ConfigureAwait(false); - return; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + cached.RemoveAll(e => predicate(e)); + dbSet.RemoveRange(dbSet.Where(predicate)); + await context.SaveChangesAsync(token).ConfigureAwait(false); + return; } public TEntity Insert(TEntity entity) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - var dbEntity = dbSet.Add(entity).Entity; - context.SaveChanges(); - cached.Add(dbEntity); - return dbEntity; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var dbEntity = dbSet.Add(entity).Entity; + context.SaveChanges(); + cached.Add(dbEntity); + return dbEntity; } public async Task InsertAsync(TEntity entity, CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - var dbEntity = dbSet.Add(entity).Entity; - await context.SaveChangesAsync(token).ConfigureAwait(false); - cached.Add(dbEntity); - return dbEntity; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var dbEntity = dbSet.Add(entity).Entity; + await context.SaveChangesAsync(token).ConfigureAwait(false); + cached.Add(dbEntity); + return dbEntity; } public IEnumerable Insert(IEnumerable newEntities) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - var dbEntities = new List(newEntities.Count()); - foreach (var item in newEntities) - dbEntities.Add(dbSet.Add(item).Entity); - context.SaveChanges(); - cached.AddRange(dbEntities); - return dbEntities; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var dbEntities = new List(newEntities.Count()); + foreach (var item in newEntities) + dbEntities.Add(dbSet.Add(item).Entity); + context.SaveChanges(); + cached.AddRange(dbEntities); + return dbEntities; } public async Task> InsertAsync(IEnumerable newEntities, CancellationToken token = default) { - cacheLocker.EnterWriteLock(); - - try - { - var dbSet = context.Set(); - var dbEntities = new List(newEntities.Count()); - foreach (var item in newEntities) - dbEntities.Add(dbSet.Add(item).Entity); - await context.SaveChangesAsync(token).ConfigureAwait(false); - cached.AddRange(dbEntities); - return dbEntities; - } - finally - { - cacheLocker.ExitWriteLock(); - } + var dbSet = context.Set(); + var dbEntities = new List(newEntities.Count()); + foreach (var item in newEntities) + dbEntities.Add(dbSet.Add(item).Entity); + await context.SaveChangesAsync(token).ConfigureAwait(false); + cached.AddRange(dbEntities); + return dbEntities; } } } diff --git a/AsbCloudInfrastructure/Services/EventService.cs b/AsbCloudInfrastructure/Services/EventService.cs index 551deef8..867abd38 100644 --- a/AsbCloudInfrastructure/Services/EventService.cs +++ b/AsbCloudInfrastructure/Services/EventService.cs @@ -9,13 +9,11 @@ namespace AsbCloudInfrastructure.Services { public class EventService : IEventService { - private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; private readonly CacheTable cacheEvents; public EventService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService) { - this.db = db; this.telemetryService = telemetryService; cacheEvents = cacheDb.GetCachedTable((AsbCloudDbContext)db); } @@ -27,30 +25,14 @@ namespace AsbCloudInfrastructure.Services var telemetryId = telemetryService.GetOrCreateTemetryIdByUid(uid); - var ids = dtos.Select(e => e.Id).ToList(); - - var dbIds = (from e in db.Events - where e.IdTelemetry == telemetryId && ids.Contains(e.IdEvent) - select e.IdEvent).ToList(); - - foreach (var dto in dtos) + var entities = dtos.Select(dto => new Event { - var entity = new Event - { - IdEvent = dto.Id, - IdTelemetry = telemetryId, - IdCategory = dto.IdCategory, - MessageTemplate = dto.Message - }; - - if (dbIds.Contains(dto.Id)) - db.Events.Update(entity); - else - db.Events.Add(entity); - } - - db.SaveChanges(); - cacheEvents.Refresh(); + IdEvent = dto.Id, + IdTelemetry = telemetryId, + IdCategory = dto.IdCategory, + MessageTemplate = dto.Message + }); + cacheEvents.Upsert(entities); } } } diff --git a/AsbCloudInfrastructure/Services/TelemetryUserService.cs b/AsbCloudInfrastructure/Services/TelemetryUserService.cs index 17e46196..ef5b59de 100644 --- a/AsbCloudInfrastructure/Services/TelemetryUserService.cs +++ b/AsbCloudInfrastructure/Services/TelemetryUserService.cs @@ -10,15 +10,13 @@ namespace AsbCloudInfrastructure.Services { public class TelemetryUserService : ITelemetryUserService { - private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; - private readonly CacheTable cacheTUsers; + private readonly CacheTable cacheTelemetryUsers; public TelemetryUserService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService) { - this.db = db; this.telemetryService = telemetryService; - cacheTUsers = cacheDb.GetCachedTable((AsbCloudDbContext)db); + cacheTelemetryUsers = cacheDb.GetCachedTable((AsbCloudDbContext)db); } public void Upsert(string uid, IEnumerable dtos) @@ -26,36 +24,18 @@ namespace AsbCloudInfrastructure.Services if (!dtos.Any()) return; - dtos = dtos.Distinct(new TelemetryUserDtoComparer()); - var telemetryId = telemetryService.GetOrCreateTemetryIdByUid(uid); - var ids = dtos.Select(e => e.Id).ToList(); - - var dbIds = (from e in db.TelemetryUsers - where e.IdTelemetry == telemetryId && ids.Contains(e.IdUser) - select e.IdUser).ToList(); - - foreach (var dto in dtos) + var entities = dtos.Distinct(new TelemetryUserDtoComparer()).Select(dto => new TelemetryUser { - var entity = new TelemetryUser - { - IdUser = dto.Id, - IdTelemetry = telemetryId, - Level = dto.Level, - Name = dto.Name, - Patronymic = dto.Patronymic, - Surname = dto.Surname, - }; - - if (dbIds.Contains(dto.Id)) - db.TelemetryUsers.Update(entity); - else - db.TelemetryUsers.Add(entity); - } - - db.SaveChanges(); - cacheTUsers.Refresh(); + IdUser = dto.Id, + IdTelemetry = telemetryId, + Level = dto.Level, + Name = dto.Name, + Patronymic = dto.Patronymic, + Surname = dto.Surname, + }); + cacheTelemetryUsers.Upsert(entities); } } } diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index 34665dfc..7635e3f7 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -1,6 +1,11 @@ -using AsbCloudDb.Model; +using AsbCloudApp.Data; +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Services; +using AsbCloudInfrastructure.Services.Cache; +using AutoMapper; using Microsoft.EntityFrameworkCore; using System; +using System.Collections.Generic; namespace ConsoleApp1 { @@ -20,10 +25,46 @@ namespace ConsoleApp1 { static void Main(string[] args) { - //var options = new DbContextOptionsBuilder() - // .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True") - // .Options; - //var context = new AsbCloudDbContext(options); + var options = new DbContextOptionsBuilder() + .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True") + .Options; + + var acfg = new MapperConfiguration(cfg => { + cfg.CreateMap(); + cfg.CreateMap(); + + cfg.CreateMap(); + cfg.CreateMap(); + + cfg.CreateMap(); + cfg.CreateMap(); + }); + + + var context = new AsbCloudDbContext(options); + var cachedDb = new CacheDb(); + var telemetryService = new TelemetryService(context, cachedDb, acfg); + var telemetryUserService = new TelemetryUserService(context, cachedDb, telemetryService); + + var tusers = new List { + new TelemetryUserDto{ + Id=1, + Level=0, + Name="Adminum", + }, + new TelemetryUserDto{ + Id=2, + Level=0, + Name="Adminum2", + }, + }; + + telemetryUserService.Upsert("123", tusers); + tusers[0].Patronymic = "Trump"; + + + telemetryUserService.Upsert("123", tusers); + //var e = new Event //{