2021-09-17 16:24:01 +05:00
using AsbCloudApp.Data ;
using AsbCloudApp.Services ;
using AsbCloudDb.Model ;
2021-11-15 14:56:11 +05:00
using AsbCloudDb ;
2021-09-17 16:24:01 +05:00
using AsbCloudInfrastructure.Services.Cache ;
using Microsoft.EntityFrameworkCore ;
using System ;
using System.Collections.Generic ;
2021-11-13 18:47:11 +05:00
using System.Diagnostics ;
2021-09-17 16:24:01 +05:00
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
namespace AsbCloudInfrastructure.Services
{
2021-09-23 10:53:48 +05:00
public abstract class TelemetryDataBaseService < TDto , TModel > : ITelemetryDataService < TDto > , IConverter < TDto , TModel >
2021-09-17 16:24:01 +05:00
where TDto : AsbCloudApp . Data . ITelemetryData
where TModel : class , AsbCloudDb . Model . ITelemetryData
{
private readonly IAsbCloudDbContext db ;
private readonly ITelemetryService telemetryService ;
protected readonly CacheTable < Telemetry > cacheTelemetry ;
protected readonly CacheTable < TelemetryUser > cacheTelemetryUsers ;
protected readonly CacheTable < Well > cacheWells ;
2021-09-23 10:53:48 +05:00
public TelemetryDataBaseService (
2021-09-17 16:24:01 +05:00
IAsbCloudDbContext db ,
ITelemetryService telemetryService ,
CacheDb cacheDb )
{
this . db = db ;
this . telemetryService = telemetryService ;
cacheTelemetry = cacheDb . GetCachedTable < Telemetry > ( ( AsbCloudDbContext ) db ) ;
cacheTelemetryUsers = cacheDb . GetCachedTable < TelemetryUser > ( ( AsbCloudDbContext ) db ) ;
cacheWells = cacheDb . GetCachedTable < Well > ( ( AsbCloudDbContext ) db ) ;
}
2021-11-15 14:56:11 +05:00
public virtual async Task < int > UpdateDataAsync ( string uid , IEnumerable < TDto > dtos , CancellationToken token = default )
2021-09-17 16:24:01 +05:00
{
if ( dtos = = default | | ! dtos . Any ( ) )
return 0 ;
2021-11-15 14:56:11 +05:00
2021-12-07 18:27:52 +05:00
var idTelemetry = telemetryService . GetOrCreateTelemetryIdByUid ( uid ) ;
2021-11-13 18:47:11 +05:00
var lastTelemetryDate = telemetryService . GetLastTelemetryDate ( uid ) ;
var dtosList = dtos . OrderBy ( d = > d . Date ) . ToList ( ) ;
2021-10-28 10:56:18 +05:00
2021-11-13 18:47:11 +05:00
var dtoMinDate = dtosList . First ( ) . Date ;
var dtoMaxDate = dtosList . Last ( ) . Date ;
if ( dtosList . Count > 1 )
{
var duplicates = new List < TDto > ( 8 ) ;
for ( int i = 1 ; i < dtosList . Count ; i + + )
2021-11-15 14:56:11 +05:00
if ( dtosList [ i ] . Date - dtosList [ i - 1 ] . Date < TimeSpan . FromMilliseconds ( 100 ) )
2021-11-13 18:47:11 +05:00
duplicates . Add ( dtosList [ i - 1 ] ) ;
2021-11-15 14:56:11 +05:00
foreach ( var duplicate in duplicates )
2021-11-13 18:47:11 +05:00
dtosList . Remove ( duplicate ) ;
}
2021-11-18 14:25:11 +05:00
var offsetHours = await telemetryService . GetTelemetryTimeZoneOffsetAsync ( idTelemetry , token ) ;
2021-10-28 10:56:18 +05:00
2021-11-18 14:25:11 +05:00
var entities = dtosList . Select ( d = > {
2021-11-17 15:54:01 +05:00
var e = Convert ( d ) ;
e . IdTelemetry = idTelemetry ;
2021-11-18 14:25:11 +05:00
if ( offsetHours is not null )
2021-11-22 11:30:08 +05:00
e . Date = telemetryService . TimeZoneService . DateToUtc ( d . Date , ( double ) offsetHours ) ;
2021-11-17 15:54:01 +05:00
return e ;
2021-11-15 14:56:11 +05:00
} ) ;
2021-09-17 16:24:01 +05:00
2021-11-15 14:56:11 +05:00
var dbset = db . Set < TModel > ( ) ;
2021-11-13 18:47:11 +05:00
try
2021-09-17 16:24:01 +05:00
{
2021-11-17 15:54:01 +05:00
return await db . Database . ExecInsertOrUpdateAsync ( dbset , entities , token ) . ConfigureAwait ( false ) ;
2021-11-13 18:47:11 +05:00
}
2021-11-15 14:56:11 +05:00
catch ( Exception ex )
2021-11-13 18:47:11 +05:00
{
2021-11-17 15:54:01 +05:00
Trace . WriteLine ( $"Fail to save data telemerty uid: {uid}, idTelemetry {idTelemetry} count: {entities.Count()} dataDate: {entities.FirstOrDefault()?.Date}. Message: {ex.Message}" ) ;
2021-11-15 14:56:11 +05:00
return 0 ;
2021-09-17 16:24:01 +05:00
}
}
public virtual async Task < IEnumerable < TDto > > GetAsync ( int idWell ,
DateTime dateBegin = default , double intervalSec = 600d ,
2021-11-22 11:30:08 +05:00
int approxPointsCount = 1024 , bool isUtc = false , CancellationToken token = default )
2021-09-17 16:24:01 +05:00
{
var well = cacheWells . FirstOrDefault ( w = > w . Id = = idWell ) ;
2021-10-27 17:48:19 +05:00
if ( well ? . IdTelemetry is null )
2021-09-17 16:24:01 +05:00
return default ;
2021-11-22 11:30:08 +05:00
var idTelemetry = well ? . IdTelemetry ? ? default ;
2021-12-03 17:34:24 +05:00
var filterByDateEnd = dateBegin ! = default ;
2021-10-27 17:48:19 +05:00
if ( dateBegin = = default )
2021-10-28 11:12:03 +05:00
{
2021-11-22 11:30:08 +05:00
dateBegin = telemetryService . GetLastTelemetryDate ( idTelemetry ) ;
2021-10-28 11:12:03 +05:00
if ( dateBegin ! = default )
dateBegin = dateBegin . AddSeconds ( - intervalSec ) ;
}
2021-09-17 16:24:01 +05:00
if ( dateBegin = = default )
dateBegin = DateTime . Now . AddSeconds ( - intervalSec ) ;
2021-10-28 11:12:03 +05:00
2021-09-29 17:05:27 +05:00
if ( dateBegin . Kind = = DateTimeKind . Unspecified )
dateBegin = DateTime . SpecifyKind ( dateBegin , DateTimeKind . Utc ) ;
2021-11-22 11:30:08 +05:00
var timeOffset = await telemetryService . GetTelemetryTimeZoneOffsetAsync ( idTelemetry , token )
. ConfigureAwait ( false ) ;
if ( timeOffset is not null )
dateBegin = telemetryService . TimeZoneService . DateToUtc ( dateBegin , timeOffset ? ? default ) ;
var dateEnd = dateBegin . AddSeconds ( intervalSec ) ;
2021-09-17 16:24:01 +05:00
var dbSet = db . Set < TModel > ( ) ;
2021-11-22 11:30:08 +05:00
var query = dbSet
. Where ( d = > d . IdTelemetry = = idTelemetry
2021-12-03 17:34:24 +05:00
& & d . Date > = dateBegin ) ;
if ( filterByDateEnd )
query = query . Where ( d = > d . Date < dateEnd ) ;
2021-09-17 16:24:01 +05:00
var fullDataCount = await query . CountAsync ( token )
. ConfigureAwait ( false ) ;
if ( fullDataCount = = 0 )
return default ;
if ( fullDataCount > 1.75 * approxPointsCount )
{
var m = ( int ) Math . Round ( 1d * fullDataCount / approxPointsCount ) ;
2021-12-01 11:08:25 +05:00
switch ( m )
{
//case var i when i <= 1: // тут для полноты, но никогда не сработает из-за условия выше
// break;
case var i when i < 10 :
query = query . Where ( ( d ) = > d . Date . Second % m = = 0 ) ;
break ;
case var i when i < 30 :
query = query . Where ( ( d ) = > ( d . Date . Minute * 60 + d . Date . Second ) % m = = 0 ) ;
break ;
case var i when i < 600 :
query = query . Where ( ( d ) = > ( ( d . Date . Hour * 60 + d . Date . Minute ) * 60 + d . Date . Second ) % m = = 0 ) ;
break ;
default :
query = query . Where ( ( d ) = > ( ( ( d . Date . DayOfYear * 24 + d . Date . Hour ) * 60 + d . Date . Minute ) * 60 + d . Date . Second ) % m = = 0 ) ;
break ;
}
2021-09-17 16:24:01 +05:00
if ( m > 1 )
2021-11-13 18:47:11 +05:00
query = query . Where ( ( d ) = > ( ( ( d . Date . DayOfYear * 24 + d . Date . Hour ) * 60 + d . Date . Minute ) * 60 + d . Date . Second ) % m = = 0 ) ;
2021-09-17 16:24:01 +05:00
}
2021-09-29 17:05:27 +05:00
var entities = await query
. OrderBy ( d = > d . Date )
. AsNoTracking ( )
. ToListAsync ( token )
. ConfigureAwait ( false ) ;
2021-09-17 16:24:01 +05:00
var dtos = entities . Select ( e = > Convert ( e ) ) ;
2021-11-18 11:24:21 +05:00
if ( isUtc )
return dtos ;
2021-11-22 11:30:08 +05:00
if ( timeOffset is null )
2021-11-18 11:24:21 +05:00
return dtos ;
dtos = dtos . Select ( d = >
{
2021-11-22 11:30:08 +05:00
d . Date = telemetryService . TimeZoneService . DateToTimeZone ( d . Date , timeOffset ? ? default ) ;
2021-11-18 11:24:21 +05:00
return d ;
} ) ;
2021-09-17 16:24:01 +05:00
return dtos ;
}
2021-11-18 11:24:21 +05:00
public virtual async Task < DatesRangeDto > GetDataDatesRangeAsync ( int idWell , bool isUtc ,
2021-09-17 16:24:01 +05:00
CancellationToken token = default )
{
var telemetryId = telemetryService . GetIdTelemetryByIdWell ( idWell ) ;
if ( telemetryId is null )
return null ;
2021-11-22 16:02:15 +05:00
var telemetry = await cacheTelemetry . FirstOrDefaultAsync ( t = > t . Id = = telemetryId , token )
2021-09-17 16:24:01 +05:00
. ConfigureAwait ( false ) ;
2021-11-22 16:02:15 +05:00
var dto = telemetryService . TelemetryTracker . GetTelemetryDateRangeByUid ( telemetry . RemoteUid ) ;
2021-11-18 11:24:21 +05:00
if ( isUtc )
2021-11-22 16:02:15 +05:00
return dto ;
2021-11-18 11:24:21 +05:00
2021-11-22 16:02:15 +05:00
dto = await telemetryService . FixDatesRangeByTimeZoneAsync ( ( int ) telemetryId , dto , token )
2021-11-18 12:03:59 +05:00
. ConfigureAwait ( false ) ;
2021-11-18 11:24:21 +05:00
2021-11-22 16:02:15 +05:00
return dto ;
2021-11-18 11:24:21 +05:00
2021-09-17 16:24:01 +05:00
}
public abstract TDto Convert ( TModel src ) ;
public abstract TModel Convert ( TDto src ) ;
}
}