This commit is contained in:
KharchenkoVV 2021-10-04 15:42:06 +05:00
commit 343d8382d9
10 changed files with 2767 additions and 224 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,133 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace AsbCloudDb.Migrations
{
public partial class Set_Telemetry_FKs_OnDelete_Cascade : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "t_telemetry_data_saub_t_telemetry_id_fk",
table: "t_telemetry_data_saub");
migrationBuilder.DropForeignKey(
name: "t_telemetry_data_spin_t_telemetry_id_fk",
table: "t_telemetry_data_spin");
migrationBuilder.DropForeignKey(
name: "t_telemetry_user_t_telemetry_id_fk",
table: "t_telemetry_user");
migrationBuilder.DropForeignKey(
name: "t_user_t_company_id_fk",
table: "t_user");
migrationBuilder.DropForeignKey(
name: "t_well_t_telemetry_id_fk",
table: "t_well");
migrationBuilder.AddForeignKey(
name: "t_telemetry_data_saub_t_telemetry_id_fk",
table: "t_telemetry_data_saub",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "t_telemetry_data_spin_t_telemetry_id_fk",
table: "t_telemetry_data_spin",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "t_telemetry_user_t_telemetry_id_fk",
table: "t_telemetry_user",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "t_user_t_company_id_fk",
table: "t_user",
column: "id_company",
principalTable: "t_company",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
migrationBuilder.AddForeignKey(
name: "t_well_t_telemetry_id_fk",
table: "t_well",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.SetNull);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "t_telemetry_data_saub_t_telemetry_id_fk",
table: "t_telemetry_data_saub");
migrationBuilder.DropForeignKey(
name: "t_telemetry_data_spin_t_telemetry_id_fk",
table: "t_telemetry_data_spin");
migrationBuilder.DropForeignKey(
name: "t_telemetry_user_t_telemetry_id_fk",
table: "t_telemetry_user");
migrationBuilder.DropForeignKey(
name: "t_user_t_company_id_fk",
table: "t_user");
migrationBuilder.DropForeignKey(
name: "t_well_t_telemetry_id_fk",
table: "t_well");
migrationBuilder.AddForeignKey(
name: "t_telemetry_data_saub_t_telemetry_id_fk",
table: "t_telemetry_data_saub",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "t_telemetry_data_spin_t_telemetry_id_fk",
table: "t_telemetry_data_spin",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "t_telemetry_user_t_telemetry_id_fk",
table: "t_telemetry_user",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "t_user_t_company_id_fk",
table: "t_user",
column: "id_company",
principalTable: "t_company",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "t_well_t_telemetry_id_fk",
table: "t_well",
column: "id_telemetry",
principalTable: "t_telemetry",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
}
}
}

View File

@ -17,10 +17,10 @@ namespace AsbCloudDb.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasPostgresExtension("adminpack")
.UseIdentityByDefaultColumns()
.HasAnnotation("Relational:Collation", "Russian_Russia.1251")
.HasAnnotation("Relational:MaxIdentifierLength", 63)
.HasAnnotation("ProductVersion", "5.0.2");
.HasAnnotation("ProductVersion", "5.0.10")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
modelBuilder.Entity("AsbCloudDb.Model.Cluster", b =>
{
@ -28,7 +28,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -64,7 +64,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -98,7 +98,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -133,7 +133,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -162,7 +162,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name")
.HasColumnType("text")
@ -274,7 +274,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int?>("IdAuthor")
.HasColumnType("integer")
@ -330,7 +330,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<Dictionary<string, object>>("Data")
.HasColumnType("jsonb")
@ -375,7 +375,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name")
.HasColumnType("text")
@ -441,7 +441,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTimeOffset>("Begin")
.HasColumnType("timestamp with time zone")
@ -490,7 +490,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<TelemetryInfo>("Info")
.HasColumnType("jsonb")
@ -518,7 +518,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("DurationSec")
.HasColumnType("integer")
@ -578,12 +578,12 @@ namespace AsbCloudDb.Migrations
.HasColumnName("is_pressure_lt_20")
.HasComment("Давление менее 20");
b.Property<bool>("IsRotorSpeedGt3")
b.Property<bool>("IsRotorSpeedGt5")
.HasColumnType("boolean")
.HasColumnName("is_rotor_speed_gt_3")
.HasComment("Обороты ротора выше 3");
b.Property<bool>("IsRotorSpeedLt3")
b.Property<bool>("IsRotorSpeedLt5")
.HasColumnType("boolean")
.HasColumnName("is_rotor_speed_lt_3")
.HasComment("Обороты ротора ниже 3");
@ -631,7 +631,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<double?>("AxialLoad")
.HasColumnType("double precision")
@ -838,7 +838,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<double?>("BreakAngleK")
.HasColumnType("double precision")
@ -1185,7 +1185,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Arg0")
.HasMaxLength(255)
@ -1282,7 +1282,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Email")
.HasMaxLength(255)
@ -1381,7 +1381,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -1415,7 +1415,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -1463,7 +1463,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("CategoryInfo")
.HasColumnType("text")
@ -1534,7 +1534,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("Code")
.HasColumnType("integer")
@ -1952,7 +1952,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -2006,7 +2006,7 @@ namespace AsbCloudDb.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.UseIdentityByDefaultColumn();
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Caption")
.HasMaxLength(255)
@ -2166,6 +2166,7 @@ namespace AsbCloudDb.Migrations
.WithMany("DataSaub")
.HasForeignKey("IdTelemetry")
.HasConstraintName("t_telemetry_data_saub_t_telemetry_id_fk")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Telemetry");
@ -2177,6 +2178,7 @@ namespace AsbCloudDb.Migrations
.WithMany("DataSpin")
.HasForeignKey("IdTelemetry")
.HasConstraintName("t_telemetry_data_spin_t_telemetry_id_fk")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Telemetry");
@ -2212,6 +2214,7 @@ namespace AsbCloudDb.Migrations
.WithMany("Users")
.HasForeignKey("IdTelemetry")
.HasConstraintName("t_telemetry_user_t_telemetry_id_fk")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Telemetry");
@ -2222,7 +2225,8 @@ namespace AsbCloudDb.Migrations
b.HasOne("AsbCloudDb.Model.Company", "Company")
.WithMany("Users")
.HasForeignKey("IdCompany")
.HasConstraintName("t_user_t_company_id_fk");
.HasConstraintName("t_user_t_company_id_fk")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("AsbCloudDb.Model.UserRole", "Role")
.WithMany("Users")
@ -2243,7 +2247,8 @@ namespace AsbCloudDb.Migrations
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
.WithOne("Well")
.HasForeignKey("AsbCloudDb.Model.Well", "IdTelemetry")
.HasConstraintName("t_well_t_telemetry_id_fk");
.HasConstraintName("t_well_t_telemetry_id_fk")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("AsbCloudDb.Model.WellType", "WellType")
.WithMany("Wells")

View File

@ -1,7 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -76,7 +75,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.DataSaub)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.ClientSetNull)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("t_telemetry_data_saub_t_telemetry_id_fk");
});
@ -85,7 +84,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.DataSpin)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.ClientSetNull)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("t_telemetry_data_spin_t_telemetry_id_fk");
});
@ -94,6 +93,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.Messages)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("t_messages_t_telemetry_id_fk");
});
@ -103,7 +103,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.Users)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.ClientSetNull)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("t_telemetry_user_t_telemetry_id_fk");
});
@ -112,6 +112,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.Analysis)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("t_analysis_t_telemetry_id_fk");
entity.HasOne(d => d.Operation)
@ -127,6 +128,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.Events)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("t_event_t_telemetry_id_fk");
});
@ -135,6 +137,7 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Company)
.WithMany(p => p.Users)
.HasForeignKey(d => d.IdCompany)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("t_user_t_company_id_fk");
entity.HasIndex(d => d.Login)
@ -151,12 +154,12 @@ namespace AsbCloudDb.Model
entity.HasOne(d => d.Telemetry)
.WithOne(p => p.Well)
.HasForeignKey<Well>(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("t_well_t_telemetry_id_fk");
});
modelBuilder.Entity<RelationCompanyWell>(entity =>
{
entity.HasKey(nameof(RelationCompanyWell.IdCompany), nameof(RelationCompanyWell.IdWell));
entity.HasOne(r => r.Well)

View File

@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
@ -8,8 +9,8 @@ namespace AsbCloudInfrastructure.Services.Cache
public class CacheDb
{
private readonly ConcurrentDictionary<string, (DateTime, object)> cache =
new ConcurrentDictionary<string, (DateTime, object)>();
private readonly Dictionary<string, (DateTime, IEnumerable)> cache =
new Dictionary<string, (DateTime, IEnumerable)>();
private readonly TimeSpan obsolesenceTime = TimeSpan.FromMinutes(15);
@ -19,7 +20,7 @@ namespace AsbCloudInfrastructure.Services.Cache
var entityTypeName = typeof(TEntity).FullName;
if (!cache.ContainsKey(entityTypeName))
cache[entityTypeName] = (DateTime.Now, new ConcurrentBag<TEntity>());
cache[entityTypeName] = (DateTime.Now, new List<TEntity>());
bool isCachedDataObsolete = DateTime.Now - cache[entityTypeName].Item1 > obsolesenceTime;

View File

@ -1,229 +1,180 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;
using System.Diagnostics;
namespace AsbCloudInfrastructure.Services.Cache
{
public class CacheTable<TEntity> : IEnumerable<TEntity>
where TEntity : class
{
private const int semaphoreTimeout = 5_000;
private static readonly SemaphoreSlim semaphore = new(1);
private readonly DbContext context;
private (DateTime refreshDate, object entities) data;
private readonly ConcurrentBag<TEntity> cached;
private (DateTime refreshDate, IEnumerable entities) data;
private readonly List<TEntity> cached;
private readonly DbSet<TEntity> dbSet;
internal CacheTable(DbContext context, (DateTime refreshDate, object entities) data)
internal CacheTable(DbContext context, (DateTime refreshDate, IEnumerable entities) data)
{
this.context = context;
this.data = data;
this.cached = (ConcurrentBag<TEntity>)data.entities;
dbSet = context.Set<TEntity>();
cached = (List<TEntity>)data.entities;
if (cached.Count == 0)
Refresh();
}
public TEntity this[int index] { get => cached.ElementAt(index); }
//public static void Sync(Action)
public int Refresh()
{
cached.Clear();
var dbEntities = context.Set<TEntity>().AsNoTracking().ToList();
foreach(var e in dbEntities)
cached.Add(e);
data.refreshDate = DateTime.Now;
var wasFree = semaphore.CurrentCount > 0;
if(!semaphore.Wait(semaphoreTimeout))
return 0;
try
{
if (wasFree)
{
cached.Clear();
var entities = dbSet.AsNoTracking().ToList();
cached.AddRange(entities);
data.refreshDate = DateTime.Now;
}
//else - nothing, it was just updated in another thread
}
catch (Exception ex)
{
Trace.WriteLine($"{DateTime.Now:yyyy.MM.dd HH:mm:ss:fff} error in CacheTable<{typeof(TEntity).Name}>.Refresh()");
Trace.WriteLine(ex.Message);
}
finally
{
semaphore.Release();
}
return cached.Count;
}
public async Task<int> RefreshAsync(CancellationToken token = default)
{
cached.Clear();
var dbEntities = await context.Set<TEntity>().AsNoTracking()
.ToListAsync(token).ConfigureAwait(false);
foreach (var e in dbEntities)
cached.Add(e);
data.refreshDate = DateTime.Now;
var wasFree = semaphore.CurrentCount > 0;
if (!await semaphore.WaitAsync(semaphoreTimeout, token).ConfigureAwait(false))
return 0;
try
{
if (wasFree)
{
cached.Clear();
var entities = await context.Set<TEntity>().AsNoTracking()
.ToListAsync(token).ConfigureAwait(false);
cached.AddRange(entities);
data.refreshDate = DateTime.Now;
}
//else - nothing, it was just updated in another thread
}
catch (Exception ex)
{
Trace.WriteLine($"{DateTime.Now:yyyy.MM.dd HH:mm:ss:fff} error in CacheTable<{typeof(TEntity).Name}>.Refresh()");
Trace.WriteLine(ex.Message);
}
finally
{
semaphore.Release();
}
return cached.Count;
}
private bool CheckRefresh(RefreshMode refreshMode)
public bool Contains(Func<TEntity, bool> predicate)
=> FirstOrDefault(predicate) != default;
public async Task<bool> ContainsAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> await FirstOrDefaultAsync(predicate, token) != default;
public TEntity FirstOrDefault()
{
if (refreshMode == RefreshMode.Force)
{
Refresh();
return true;
}
if ((refreshMode == RefreshMode.IfResultEmpty) && !cached.Any())
{
Refresh();
return true;
}
return false;
}
private async Task<bool> CheckRefreshAsync(RefreshMode refreshMode, CancellationToken token = default)
{
if (refreshMode == RefreshMode.Force)
{
await RefreshAsync(token);
return true;
}
if (refreshMode == RefreshMode.IfResultEmpty && !cached.Any())
{
await RefreshAsync(token);
return true;
}
return false;
}
public bool Contains(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
=> FirstOrDefault(predicate, refreshMode) != default;
public Task<bool> ContainsAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> ContainsAsync(predicate, RefreshMode.IfResultEmpty, token);
public async Task<bool> ContainsAsync(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
=> await FirstOrDefaultAsync(predicate, refreshMode, token) != default;
public Task<TEntity> FirstOrDefaultAsync(CancellationToken token = default)
=> FirstOrDefaultAsync(RefreshMode.IfResultEmpty, token);
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;
if (result != default)
return result;
Refresh();
return cached.FirstOrDefault();
}
public async Task<TEntity> FirstOrDefaultAsync(RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
public async Task<TEntity> FirstOrDefaultAsync(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;
if (result != default)
return result;
await RefreshAsync(token);
return cached.FirstOrDefault();
}
public Task<TEntity> FirstOrDefaultAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> FirstOrDefaultAsync(predicate, RefreshMode.IfResultEmpty, token);
public TEntity FirstOrDefault(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
public TEntity FirstOrDefault(Func<TEntity, bool> predicate)
{
bool isUpdated = CheckRefresh(refreshMode);
var result = cached.FirstOrDefault(predicate);
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
Refresh();
return cached.FirstOrDefault(predicate);
}
return result;
if (result != default)
return result;
Refresh();
return cached.FirstOrDefault(predicate);
}
public async Task<TEntity> FirstOrDefaultAsync(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
public async Task<TEntity> FirstOrDefaultAsync(Func<TEntity, bool> predicate, 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;
if (result != default)
return result;
await RefreshAsync(token);
return cached.FirstOrDefault(predicate);
}
public Task<IEnumerable<TEntity>> WhereAsync(CancellationToken token = default)
=> WhereAsync(default, RefreshMode.IfResultEmpty, token);
public Task<IEnumerable<TEntity>> WhereAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> WhereAsync(predicate, RefreshMode.IfResultEmpty, token);
public IEnumerable<TEntity> Where(Func<TEntity, bool> predicate = default, RefreshMode refreshMode = RefreshMode.IfResultEmpty)
public IEnumerable<TEntity> Where(Func<TEntity, bool> predicate = default)
{
bool isUpdated = CheckRefresh(refreshMode);
var result = (predicate != default)
? cached.Where(predicate)
: cached;
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
Refresh();
result = (predicate != default)
? cached.Where(predicate)
: cached;
}
if (result.Any())
return result;
Refresh();
result = (predicate != default)
? cached.Where(predicate)
: cached;
return result;
}
public async Task<IEnumerable<TEntity>> WhereAsync(Func<TEntity, bool> predicate = default,
RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default)
CancellationToken token = default)
{
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
var result = (predicate != default)
? cached.Where(predicate)
: cached;
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
await RefreshAsync(token);
result = (predicate != default)
? cached.Where(predicate)
: cached;
}
if (result.Any())
return result;
await RefreshAsync(token);
result = (predicate != default)
? cached.Where(predicate)
: cached;
return result;
}
//public IEnumerable<TEntity> Mutate(Func<TEntity, bool> predicate,
// Action<TEntity> mutation)
//{
// var dbEntities = dbSet.Where(predicate);
// if (dbEntities.Any())
// {
// foreach (var dbEntity in dbEntities)
// mutation(dbEntity);
// context.SaveChanges();
// }
// var matchedByPredicate = cached.Select(el => predicate(el));
// foreach (var item in matchedByPredicate)
// cached.TryTake(out var t);
// cached = cached.RemoveAll(e => predicate(e));
// foreach (var e in dbEntities)
// cached.Add(e);
// return dbEntities;
//}
//public async Task<IEnumerable<TEntity>> MutateAsync(Func<TEntity,
// bool> predicate, Action<TEntity> mutation, CancellationToken token = default)
//{
// 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));
// foreach (var e in dbEntities)
// cached.Add(e);
// return dbEntities;
//}
public TEntity Upsert(TEntity entity)
{
var updated = dbSet.Update(entity);
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> updated;
if (dbSet.Contains(entity))
updated = dbSet.Update(entity);
else
updated = dbSet.Add(entity);
context.SaveChanges();
Refresh();
return updated.Entity;
@ -295,7 +246,7 @@ namespace AsbCloudInfrastructure.Services.Cache
{
var entry = dbSet.Add(entity);
context.SaveChanges();
cached.Add(entry.Entity);
Refresh();
return entry.Entity;
}
@ -303,34 +254,28 @@ namespace AsbCloudInfrastructure.Services.Cache
{
var entry = dbSet.Add(entity);
await context.SaveChangesAsync(token).ConfigureAwait(false);
cached.Add(entry.Entity);
await RefreshAsync(token).ConfigureAwait(false);
return entry.Entity;
}
public IEnumerable<TEntity> Insert(IEnumerable<TEntity> newEntities)
public int Insert(IEnumerable<TEntity> newEntities)
{
var dbEntities = new List<TEntity>(newEntities.Count());
foreach (var item in newEntities)
dbEntities.Add(dbSet.Add(item).Entity);
context.SaveChanges();
foreach (var e in dbEntities)
cached.Add(e);
return dbEntities;
dbSet.AddRange(newEntities);
var result = context.SaveChanges();
Refresh();
return result;
}
public async Task<IEnumerable<TEntity>> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default)
public async Task<int> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default)
{
var dbEntities = new List<TEntity>(newEntities.Count());
foreach (var item in newEntities)
dbEntities.Add(dbSet.Add(item).Entity);
await context.SaveChangesAsync(token).ConfigureAwait(false);
foreach (var e in dbEntities)
cached.Add(e);
return dbEntities;
dbSet.AddRange(newEntities);
var result = await context.SaveChangesAsync(token).ConfigureAwait(false);
await RefreshAsync(token).ConfigureAwait(false);
return result;
}
public IEnumerator<TEntity> GetEnumerator() => Where().GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}

View File

@ -1,4 +0,0 @@
namespace AsbCloudInfrastructure.Services.Cache
{
public enum RefreshMode { None, IfResultEmpty, Force, }
}

View File

@ -8,6 +8,7 @@ using System.Linq;
using System;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using System.Threading;
namespace AsbCloudInfrastructure.Services
{
@ -229,11 +230,11 @@ namespace AsbCloudInfrastructure.Services
transaction.Commit();
sw.Stop();
Console.WriteLine($"Successfully commited in {1d*sw.ElapsedMilliseconds/1000d: #0.00} sec.");
Console.WriteLine($"Successfully commited in {1d*sw.ElapsedMilliseconds/1000d: #0.00} sec. Affected {rows} rows.");
}
catch(Exception ex)
{
Console.WriteLine("Fail. Rollback.");
Console.WriteLine($"Fail. Rollback. Reason is:{ex.Message}");
transaction.Rollback();
return 0;
}

View File

@ -17,8 +17,6 @@ namespace AsbCloudWebApi
{
services.AddSwaggerGen(c =>
{
//c.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["controller"]}_{e.HttpMethod}");
//c.CustomOperationIds(e => $"{e.HttpMethod}_{e.ActionDescriptor.Ac");
c.CustomOperationIds(e =>
{
return $"{e.ActionDescriptor.RouteValues["action"]}";

View File

@ -9,6 +9,8 @@ using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore;
using AsbCloudInfrastructure.Services.Cache;
using AsbCloudInfrastructure.Services;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp1
{
@ -17,11 +19,99 @@ namespace ConsoleApp1
// .Options;
//var context = new AsbCloudDbContext(options);
class Program
{
{
static object lockObject = new();
static int inc = 0;
static void RefreshMonitor()
{
if (Monitor.TryEnter(lockObject))
{
Task.Delay(2_000);
Interlocked.Increment(ref inc);
}
else
Monitor.Wait(lockObject);
}
//static Mutex mutex = new Mutex();
//static void RefreshMutex()
//{
// if(Mutex.TryOpenExisting()
// {
// }
// Interlocked.Increment(ref inc);
//}
static bool isUnLocked = true;
static void RefreshBool() {
if(isUnLocked)
{
isUnLocked = false;
Console.WriteLine(".");
Task.Delay(50).Wait();
inc++;
isUnLocked = true;
}
while(!isUnLocked)
Task.Delay(10).Wait();
}
static readonly SemaphoreSlim semaphore = new(1);
static void Refresh()
{
var wasFree = semaphore.CurrentCount > 0;
semaphore.Wait();
if (wasFree)
{
Console.WriteLine(".");
Task.Delay(500).Wait();
inc++;
}
semaphore.Release();
}
static async Task RefreshAsync()
{
var wasFree = semaphore.CurrentCount == 1;
await semaphore.WaitAsync();
if (wasFree)
{
Console.WriteLine(".");
await Task.Delay(500);
inc++;
}else
Console.Write(",");
semaphore.Release();
}
static void Main(/*string[] args*/)
{
Console.WriteLine(DateTime.Now.ToString("mm:ss.fff"));
//semaphore.Release();
Refresh();
for (int i= 0; i < 4; i++)
{
var ts = new List<Task>(100);
for (int j = 0; j < 20; j++)
{
ts.Add(
Task.Run( RefreshAsync));
}
Task.WaitAll(ts.ToArray());
Console.WriteLine("*");
}
Console.WriteLine("_");
Console.ReadKey();
Console.WriteLine(inc);
return;
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
.Options;