forked from ddrilling/AsbCloudServer
252 lines
11 KiB
C#
252 lines
11 KiB
C#
using AsbCloudApp.Data;
|
||
using AsbCloudApp.Services;
|
||
using AsbCloudDb.Model;
|
||
using AsbCloudInfrastructure.Services.Cache;
|
||
using Mapster;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System;
|
||
using Microsoft.EntityFrameworkCore;
|
||
|
||
namespace AsbCloudInfrastructure.Services
|
||
{
|
||
public class TelemetryService : ITelemetryService
|
||
{
|
||
private readonly CacheTable<Telemetry> cacheTelemetry;
|
||
private readonly CacheTable<Well> cacheWells;
|
||
private readonly IAsbCloudDbContext db;
|
||
private readonly ITelemetryTracker telemetryTracker;
|
||
|
||
public TelemetryService(IAsbCloudDbContext db, ITelemetryTracker telemetryTracker,
|
||
CacheDb cacheDb)
|
||
{
|
||
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
|
||
cacheWells = cacheDb.GetCachedTable<Well>((AsbCloudDbContext)db);
|
||
this.db = db;
|
||
this.telemetryTracker = telemetryTracker;
|
||
}
|
||
|
||
public IEnumerable<TelemetryDto> GetTransmittingTelemetriesAsync(int idCompany)
|
||
{
|
||
var telemetryDtos = new List<TelemetryDto>();
|
||
IEnumerable<string> activeTelemetriesUids = telemetryTracker.GetTransmittingTelemetriesUids();
|
||
if (activeTelemetriesUids.Any())
|
||
{
|
||
var telemetries = cacheTelemetry
|
||
.Where(t => activeTelemetriesUids.Contains(t.RemoteUid));
|
||
telemetryDtos = telemetries.Adapt<TelemetryDto>().ToList();
|
||
}
|
||
|
||
return telemetryDtos;
|
||
}
|
||
|
||
public void SaveRequestDate(string uid, DateTime remoteDate) =>
|
||
telemetryTracker.SaveRequestDate(uid, remoteDate);
|
||
|
||
public DateTime GetLastTelemetryDate(string telemetryUid) =>
|
||
telemetryTracker.GetLastTelemetryDateByUid(telemetryUid);
|
||
|
||
public DateTime GetLastTelemetryDate(int telemetryId)
|
||
{
|
||
var lastTelemetryDate = DateTime.MinValue;
|
||
var telemetry = cacheTelemetry.FirstOrDefault(t => t.Id == telemetryId);
|
||
|
||
if (telemetry is null)
|
||
return lastTelemetryDate;
|
||
|
||
var uid = telemetry.RemoteUid;
|
||
|
||
lastTelemetryDate = GetLastTelemetryDate(uid);
|
||
return lastTelemetryDate;
|
||
}
|
||
|
||
public int GetOrCreateTemetryIdByUid(string uid)
|
||
=> GetOrCreateTelemetryByUid(uid).Id;
|
||
|
||
public int? GetidWellByTelemetryUid(string uid)
|
||
=> GetWellByTelemetryUid(uid)?.Id;
|
||
|
||
public double GetTimezoneOffsetByTelemetryId(int idTelemetry) =>
|
||
cacheTelemetry.FirstOrDefault(t => t.Id == idTelemetry).Info?.TimeZoneOffsetTotalHours ?? 0d;
|
||
|
||
public void UpdateInfo(string uid, TelemetryInfoDto info)
|
||
{
|
||
var telemetry = GetOrCreateTelemetryByUid(uid);
|
||
telemetry.Info = info.Adapt<TelemetryInfo>();
|
||
cacheTelemetry.Upsert(telemetry);
|
||
}
|
||
|
||
public int? GetIdTelemetryByIdWell(int idWell)
|
||
{
|
||
var well = cacheWells.FirstOrDefault(w => w.Id == idWell);
|
||
if (well is null)
|
||
return null;
|
||
|
||
return well.IdTelemetry;
|
||
}
|
||
|
||
private Well GetWellByTelemetryUid(string uid)
|
||
{
|
||
var tele = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid);
|
||
if (tele is null)
|
||
return null;
|
||
|
||
return cacheWells.FirstOrDefault(w => w?.IdTelemetry == tele.Id);
|
||
}
|
||
|
||
private Telemetry GetOrCreateTelemetryByUid(string uid)
|
||
=> cacheTelemetry.GetOrCreate(t => t.RemoteUid == uid, () => new Telemetry { RemoteUid = uid });
|
||
|
||
public IEnumerable<(string Key, int[] Ids)> GetRedundentRemoteUids()
|
||
{
|
||
return db.Telemetries
|
||
.ToList()
|
||
.GroupBy(t => t.RemoteUid)
|
||
.Where(g => g.Count() > 1)
|
||
.Select(g => (g.Key, g.Select(t=>t.Id).ToArray()));
|
||
}
|
||
|
||
public int Merge(IEnumerable<int> telemetryIds)
|
||
{
|
||
if (telemetryIds.Count() < 2)
|
||
throw new ArgumentException($"telemetryIds {telemetryIds} < 2. nothing to merge.", nameof(telemetryIds));
|
||
|
||
// найти телеметрию с наиболее полными справочниками и принять её за основную
|
||
// отделить основную от остальных
|
||
|
||
// Оценка трудоебкости
|
||
var telemetriesGrade = db.Telemetries
|
||
.Include(t => t.Messages)
|
||
.Include(t => t.DataSaub)
|
||
.Include(t => t.DataSpin)
|
||
.Include(t => t.Well)
|
||
.Where(t => telemetryIds.Contains(t.Id))
|
||
.Select(t => new {
|
||
t.Id,
|
||
t.RemoteUid,
|
||
t.Info,
|
||
IdWell = t.Well != null ? t.Well.Id : int.MinValue,
|
||
Records = t.Messages.Count + t.DataSaub.Count + t.DataSpin.Count,
|
||
EventsAny = t.Events.Any(),
|
||
UsersAny = t.Users.Any(),
|
||
})
|
||
.OrderByDescending(t=>t.Records)
|
||
.ToList();
|
||
|
||
var telemetryDestId = telemetriesGrade.FirstOrDefault().Id;
|
||
if (telemetryDestId == default)
|
||
return 0;
|
||
|
||
var telemetriesSrcIds = telemetryIds.Where(t => t != telemetryDestId).ToList();
|
||
if(!telemetriesSrcIds.Any())
|
||
return 0;
|
||
|
||
var telemetriesSrcIdsSql = $"({string.Join(',', telemetriesSrcIds)})";
|
||
|
||
var (RemoteUid, Info) = telemetriesGrade
|
||
.Where(t => t.Info != null)
|
||
.OrderByDescending(t => t.Id)
|
||
.Select(t => (t.RemoteUid, t.Info))
|
||
.FirstOrDefault();
|
||
|
||
var wellId = telemetriesGrade
|
||
.Where(t => t.IdWell > 0)
|
||
.OrderByDescending(t => t.Id)
|
||
.Select(t => t.IdWell)
|
||
.FirstOrDefault();
|
||
|
||
// начало изменений
|
||
Console.WriteLine($"Start merge telemetries ids: [{string.Join(',', telemetriesSrcIds)}] to {telemetryDestId}");
|
||
var sw = new System.Diagnostics.Stopwatch();
|
||
sw.Start();
|
||
var transaction = db.Database.BeginTransaction();
|
||
int rows = 0;
|
||
try
|
||
{
|
||
var telemetryDst = db.Telemetries.FirstOrDefault(t => t.Id == telemetryDestId);
|
||
telemetryDst.RemoteUid = RemoteUid;
|
||
telemetryDst.Info = Info;
|
||
|
||
if (wellId != default)
|
||
{
|
||
var well = db.Wells.FirstOrDefault(w => w.Id == wellId);
|
||
well.IdTelemetry = telemetryDestId;
|
||
}
|
||
|
||
// events merge
|
||
var telemetryDstEventsIds = db.TelemetryEvents.Where(t => t.IdTelemetry == telemetryDestId).Select(t => t.IdEvent).ToList();
|
||
var telemetrySrcEvents = db.TelemetryEvents
|
||
.Where(t => telemetriesSrcIds.Contains(t.IdTelemetry) && !telemetryDstEventsIds.Contains(t.IdEvent))
|
||
.Select(t => new TelemetryEvent
|
||
{
|
||
IdTelemetry = telemetryDestId,
|
||
IdEvent = t.IdEvent,
|
||
IdCategory = t.IdCategory,
|
||
MessageTemplate = t.MessageTemplate,
|
||
})
|
||
.ToList();
|
||
var telemetryEventNewUniq = new Dictionary<int, TelemetryEvent>();
|
||
foreach (var telemetryEvent in telemetrySrcEvents)
|
||
telemetryEventNewUniq[telemetryEvent.IdEvent] = telemetryEvent;
|
||
if (telemetrySrcEvents.Any())
|
||
db.TelemetryEvents.AddRange(telemetryEventNewUniq.Values);
|
||
|
||
// users merge
|
||
var telemetryDstUsersIds = db.TelemetryUsers.Where(t => t.IdTelemetry == telemetryDestId).Select(t => t.IdUser).ToList();
|
||
var telemetrySrcUsers = db.TelemetryUsers
|
||
.Where(t => telemetriesSrcIds.Contains(t.IdTelemetry) && !telemetryDstUsersIds.Contains(t.IdUser))
|
||
.Select(t => new TelemetryUser
|
||
{
|
||
IdTelemetry = telemetryDestId,
|
||
IdUser = t.IdUser,
|
||
Level = t.Level,
|
||
Name = t.Name,
|
||
Patronymic = t.Patronymic,
|
||
Surname = t.Surname,
|
||
}).ToList();
|
||
var telemetryUserNewUniq = new Dictionary<int, TelemetryUser>();
|
||
foreach (var telemetryUser in telemetrySrcUsers)
|
||
telemetryUserNewUniq[telemetryUser.IdUser] = telemetryUser;
|
||
if (telemetrySrcUsers.Any())
|
||
db.TelemetryUsers.AddRange(telemetryUserNewUniq.Values);
|
||
|
||
db.SaveChanges();
|
||
|
||
db.Database.SetCommandTimeout(3_000); // 5 мин
|
||
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_data_saub DISABLE TRIGGER ALL;");
|
||
rows += db.Database.ExecuteSqlRaw($"UPDATE t_telemetry_data_saub SET id_telemetry = {telemetryDestId} WHERE id_telemetry IN {telemetriesSrcIdsSql};");
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_data_saub ENABLE TRIGGER ALL;");
|
||
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_data_spin DISABLE TRIGGER ALL;");
|
||
rows += db.Database.ExecuteSqlRaw($"UPDATE t_telemetry_data_spin SET id_telemetry = {telemetryDestId} WHERE id_telemetry IN {telemetriesSrcIdsSql};");
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_data_spin ENABLE TRIGGER ALL;");
|
||
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_analysis DISABLE TRIGGER ALL;");
|
||
rows += db.Database.ExecuteSqlRaw($"UPDATE t_telemetry_analysis SET id_telemetry = {telemetryDestId} WHERE id_telemetry IN {telemetriesSrcIdsSql};");
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_analysis ENABLE TRIGGER ALL;");
|
||
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_message DISABLE TRIGGER ALL;");
|
||
rows += db.Database.ExecuteSqlRaw($"UPDATE t_telemetry_message SET id_telemetry = {telemetryDestId} WHERE id_telemetry IN {telemetriesSrcIdsSql};");
|
||
db.Database.ExecuteSqlRaw($"ALTER TABLE t_telemetry_message ENABLE TRIGGER ALL;");
|
||
|
||
rows += db.Database.ExecuteSqlRaw($"DELETE FROM t_telemetry_event WHERE id_telemetry IN {telemetriesSrcIdsSql};");
|
||
rows += db.Database.ExecuteSqlRaw($"DELETE FROM t_telemetry_user WHERE id_telemetry IN {telemetriesSrcIdsSql};");
|
||
rows += db.Database.ExecuteSqlRaw($"DELETE FROM t_telemetry WHERE id IN {telemetriesSrcIdsSql};");
|
||
|
||
transaction.Commit();
|
||
sw.Stop();
|
||
Console.WriteLine($"Successfully commited in {1d*sw.ElapsedMilliseconds/1000d: #0.00} sec. Affected {rows} rows.");
|
||
}
|
||
catch(Exception ex)
|
||
{
|
||
Console.WriteLine($"Fail. Rollback. Reason is:{ex.Message}");
|
||
transaction.Rollback();
|
||
return 0;
|
||
}
|
||
|
||
return rows;
|
||
}
|
||
}
|
||
}
|