forked from ddrilling/AsbCloudServer
170 lines
6.2 KiB
C#
170 lines
6.2 KiB
C#
using AsbCloudApp.Requests;
|
|
using AsbCloudApp.Services;
|
|
using AsbCloudDb.Model;
|
|
using Mapster;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AsbCloudInfrastructure.Repository
|
|
{
|
|
public class WitsRecordRepository<TDto, TEntity> : IWitsRecordRepository<TDto>
|
|
where TEntity : AsbCloudDb.Model.WITS.RecordBase, ITelemetryData
|
|
where TDto : AsbCloudApp.Data.ITelemetryData
|
|
{
|
|
private static readonly Random random = new Random((int)(DateTime.Now.Ticks % 0xFFFFFFFF));
|
|
private readonly DbSet<TEntity> dbset;
|
|
private readonly IAsbCloudDbContext db;
|
|
private readonly ITelemetryService telemetryService;
|
|
|
|
private static readonly ConcurrentDictionary<int, TDto> cache = new();
|
|
|
|
public WitsRecordRepository(IAsbCloudDbContext db, ITelemetryService telemetryService)
|
|
{
|
|
dbset = db.Set<TEntity>();
|
|
this.db = db;
|
|
this.telemetryService = telemetryService;
|
|
}
|
|
|
|
public async Task<(DateTime begin, DateTime end, int count)?> GetStatAsync(int idTelemetry, CancellationToken token)
|
|
{
|
|
var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours;
|
|
var stat = await dbset.Where(d => d.IdTelemetry == idTelemetry)
|
|
.GroupBy(d => d.IdTelemetry)
|
|
.Select(g => new Tuple<DateTimeOffset, DateTimeOffset, int>(g.Min(d => d.DateTime), g.Max(d => d.DateTime), g.Count()))
|
|
.FirstOrDefaultAsync(token);
|
|
|
|
if (stat is null || stat.Item3 == 0)
|
|
return null;
|
|
|
|
return (
|
|
stat.Item1.ToRemoteDateTime(timezoneHours),
|
|
stat.Item2.ToRemoteDateTime(timezoneHours),
|
|
stat.Item3);
|
|
}
|
|
|
|
public async Task<IEnumerable<TDto>> GetAsync(int idTelemetry, DateTime begin, DateTime end, CancellationToken token)
|
|
{
|
|
var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours;
|
|
var query = dbset
|
|
.Where(d => d.IdTelemetry == idTelemetry)
|
|
.Where(d => d.DateTime >= begin)
|
|
.Where(d => d.DateTime <= end)
|
|
.AsNoTracking();
|
|
var data = await query.ToListAsync(token);
|
|
return data.Select(d => Convert(d, timezoneHours));
|
|
}
|
|
|
|
private IQueryable<TEntity> BuildQuery(TelemetryPartDeleteRequest request)
|
|
{
|
|
var query = db.Set<TEntity>()
|
|
.Where(o => o.IdTelemetry == request.IdTelemetry);
|
|
|
|
if (request.LeDate is not null)
|
|
{
|
|
var leDate = request.LeDate.Value.ToUniversalTime();
|
|
query = query.Where(o => o.DateTime <= leDate);
|
|
}
|
|
|
|
if (request.GeDate is not null)
|
|
{
|
|
var geDate = request.GeDate.Value.ToUniversalTime();
|
|
query = query.Where(o => o.DateTime >= geDate);
|
|
}
|
|
|
|
return query;
|
|
}
|
|
|
|
public async Task<int> DeleteAsync(TelemetryPartDeleteRequest request, CancellationToken token)
|
|
{
|
|
var query = BuildQuery(request);
|
|
dbset.RemoveRange(query);
|
|
return await db.SaveChangesAsync(token);
|
|
}
|
|
|
|
public TDto? GetLastOrDefault(int idTelemetry)
|
|
=> cache.GetValueOrDefault(idTelemetry);
|
|
|
|
public async Task SaveDataAsync(int idTelemetry, IEnumerable<TDto> dtos, CancellationToken token)
|
|
{
|
|
if (!dtos.Any())
|
|
return;
|
|
|
|
cache.AddOrUpdate(idTelemetry, dtos.Last(), (_, _) => dtos.OrderBy(r => r.DateTime).Last());
|
|
|
|
var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours;
|
|
var entities = dtos
|
|
.DistinctBy(d => d.DateTime)
|
|
.Select(dto => Convert(dto, idTelemetry, timezoneHours));
|
|
|
|
var dateMin = entities.Min(e => e.DateTime);
|
|
var dateMax = entities.Max(e => e.DateTime);
|
|
var existingEntities = await db.Set<AsbCloudDb.Model.WITS.RecordBase>()
|
|
.Where(e => e.IdTelemetry == idTelemetry)
|
|
.Where(e => e.DateTime >= dateMin && e.DateTime <= dateMax)
|
|
.Select(e => e.DateTime)
|
|
.OrderBy(d => d)
|
|
.ToArrayAsync(token);
|
|
|
|
foreach (var entity in entities)
|
|
{
|
|
if (!existingEntities.Any(e => e == entity.DateTime))
|
|
{
|
|
dbset.Add(entity);
|
|
}
|
|
else
|
|
{
|
|
var dt = entity.DateTime;
|
|
entity.DateTime = new DateTimeOffset(
|
|
dt.Year,
|
|
dt.Month,
|
|
dt.Day,
|
|
dt.Hour,
|
|
dt.Minute,
|
|
dt.Second,
|
|
(dt.Millisecond + random.Next(1, 283)) % 1000,
|
|
dt.Offset);
|
|
dbset.Add(entity);
|
|
}
|
|
}
|
|
|
|
await db.SaveChangesAsync(token);
|
|
}
|
|
|
|
private static short GetRecId(TDto dto)
|
|
{
|
|
var recid = dto switch
|
|
{
|
|
AsbCloudApp.Data.WITS.Record1Dto _ => 1,
|
|
AsbCloudApp.Data.WITS.Record7Dto _ => 7,
|
|
AsbCloudApp.Data.WITS.Record8Dto _ => 8,
|
|
AsbCloudApp.Data.WITS.Record50Dto _ => 50,
|
|
AsbCloudApp.Data.WITS.Record60Dto _ => 60,
|
|
AsbCloudApp.Data.WITS.Record61Dto _ => 61,
|
|
_ => 0,
|
|
};
|
|
return (short)recid;
|
|
}
|
|
|
|
private static TEntity Convert(TDto dto, int idTelemetry, double timezoneHours)
|
|
{
|
|
var entity = dto.Adapt<TEntity>();
|
|
entity.Recid = GetRecId(dto);
|
|
entity.IdTelemetry = idTelemetry;
|
|
entity.DateTime = dto.DateTime.ToUtcDateTimeOffset(timezoneHours);
|
|
return entity;
|
|
}
|
|
|
|
private static TDto Convert(TEntity entity, double timezoneHours)
|
|
{
|
|
var data = entity.Adapt<TDto>();
|
|
data.DateTime = entity.DateTime.ToRemoteDateTime(timezoneHours);
|
|
return data;
|
|
}
|
|
}
|
|
}
|