Compare commits

..

2 Commits

Author SHA1 Message Date
ngfrolov
58aa41c1b9
New tagBag scheme tested
All checks were successful
Unit tests / test (push) Successful in 1m37s
2024-12-25 13:27:14 +05:00
ngfrolov
4fa5423265
Stress test with results
All checks were successful
Unit tests / test (push) Successful in 1m6s
2024-12-24 16:12:46 +05:00
75 changed files with 1207 additions and 519 deletions

View File

@ -31,7 +31,7 @@ jobs:
- name: Setup dotnet - name: Setup dotnet
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: 9.0.x dotnet-version: 8.0.x
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run integration tests - name: Run integration tests

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
@ -16,10 +16,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" /> <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -16,6 +16,12 @@ namespace DD.Persistence.API;
public static class DependencyInjection public static class DependencyInjection
{ {
//public static void MapsterSetup()
//{
// TypeAdapterConfig.GlobalSettings.Default.Config
// .ForType<TechMessageDto, TechMessage>()
// .Ignore(dest => dest.System, dest => dest.SystemId);
//}
public static void AddSwagger(this IServiceCollection services, IConfiguration configuration) public static void AddSwagger(this IServiceCollection services, IConfiguration configuration)
{ {
services.AddSwaggerGen(c => services.AddSwaggerGen(c =>

View File

@ -26,6 +26,8 @@ public class Startup
services.AddJWTAuthentication(Configuration); services.AddJWTAuthentication(Configuration);
services.AddMemoryCache(); services.AddMemoryCache();
services.AddServices(); services.AddServices();
//DependencyInjection.MapsterSetup();
} }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>8dcdcfed-c959-4eef-9891-ae60b1b136ea</UserSecretsId> <UserSecretsId>8dcdcfed-c959-4eef-9891-ae60b1b136ea</UserSecretsId>
@ -14,9 +14,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -20,6 +20,5 @@
"clientId": "webapi", "clientId": "webapi",
"grantType": "password", "grantType": "password",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "7d9f3574-6574-4ca3-845a-0276eb4aa8f6" "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "7d9f3574-6574-4ca3-845a-0276eb4aa8f6"
}, }
"ClientUrl": "http://localhost:5000/"
} }

View File

@ -3,16 +3,15 @@ using DD.Persistence.Client.Clients.Base;
using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Models; using DD.Persistence.Models;
using DD.Persistence.Models.Requests; using DD.Persistence.Models.Requests;
using DD.Persistence.Client.Clients.Interfaces.Refit;
namespace DD.Persistence.Client.Clients; namespace DD.Persistence.Client.Clients;
public class ChangeLogClient : BaseClient, IChangeLogClient public class ChangeLogClient : BaseClient, IChangeLogClient
{ {
private readonly IRefitChangeLogClient refitChangeLogClient; private readonly Interfaces.Refit.IRefitChangeLogClient refitChangeLogClient;
public ChangeLogClient(IRefitClientFactory<IRefitChangeLogClient> refitClientFactory, ILogger<ChangeLogClient> logger) : base(logger) public ChangeLogClient(Interfaces.Refit.IRefitChangeLogClient refitChangeLogClient, ILogger<ChangeLogClient> logger) : base(logger)
{ {
this.refitChangeLogClient = refitClientFactory.Create(); this.refitChangeLogClient = refitChangeLogClient;
} }
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token) public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)

View File

@ -9,9 +9,9 @@ public class DataSourceSystemClient : BaseClient, IDataSourceSystemClient
{ {
private readonly IRefitDataSourceSystemClient dataSourceSystemClient; private readonly IRefitDataSourceSystemClient dataSourceSystemClient;
public DataSourceSystemClient(IRefitClientFactory<IRefitDataSourceSystemClient> dataSourceSystemClientFactory, ILogger<DataSourceSystemClient> logger) : base(logger) public DataSourceSystemClient(IRefitDataSourceSystemClient dataSourceSystemClient, ILogger<DataSourceSystemClient> logger) : base(logger)
{ {
this.dataSourceSystemClient = dataSourceSystemClientFactory.Create(); this.dataSourceSystemClient = dataSourceSystemClient;
} }
public async Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token) public async Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token)

View File

@ -6,7 +6,7 @@ namespace DD.Persistence.Client.Clients.Interfaces;
/// Клиент для работы с временными данными /// Клиент для работы с временными данными
/// </summary> /// </summary>
/// <typeparam name="TDto"></typeparam> /// <typeparam name="TDto"></typeparam>
public interface ITimeSeriesClient<TDto> : IDisposable where TDto : class, ITimeSeriesAbstractDto public interface ITimeSeriesClient<TDto> : IDisposable where TDto : class, new()
{ {
/// <summary> /// <summary>
/// Добавление записей /// Добавление записей

View File

@ -4,7 +4,7 @@ using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit; namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitChangeLogClient : IRefitClient, IDisposable public interface IRefitChangeLogClient : IDisposable
{ {
private const string BaseRoute = "/api/ChangeLog"; private const string BaseRoute = "/api/ChangeLog";

View File

@ -1,10 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitClient
{
}

View File

@ -2,7 +2,7 @@
using Refit; using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit; namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitDataSourceSystemClient : IRefitClient, IDisposable public interface IRefitDataSourceSystemClient : IDisposable
{ {
private const string BaseRoute = "/api/dataSourceSystem"; private const string BaseRoute = "/api/dataSourceSystem";

View File

@ -3,7 +3,7 @@ using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit; namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitSetpointClient : IRefitClient, IDisposable public interface IRefitSetpointClient : IDisposable
{ {
private const string BaseRoute = "/api/setpoint"; private const string BaseRoute = "/api/setpoint";

View File

@ -1,10 +1,11 @@
using DD.Persistence.Models; using Microsoft.AspNetCore.Mvc;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests; using DD.Persistence.Models.Requests;
using Refit; using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit namespace DD.Persistence.Client.Clients.Interfaces.Refit
{ {
public interface IRefitTechMessagesClient : IRefitClient, IDisposable public interface IRefitTechMessagesClient : IDisposable
{ {
private const string BaseRoute = "/api/techMessages"; private const string BaseRoute = "/api/techMessages";

View File

@ -2,8 +2,8 @@ using DD.Persistence.Models;
using Refit; using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit; namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitTimeSeriesClient<TDto> : IRefitClient, IDisposable public interface IRefitTimeSeriesClient<TDto> : IDisposable
where TDto : class, ITimeSeriesAbstractDto where TDto : class, new()
{ {
private const string BaseRoute = "/api/dataSaub"; private const string BaseRoute = "/api/dataSaub";

View File

@ -3,7 +3,7 @@ using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit; namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitTimestampedSetClient : IRefitClient, IDisposable public interface IRefitTimestampedSetClient : IDisposable
{ {
private const string baseUrl = "/api/TimestampedSet/{idDiscriminator}"; private const string baseUrl = "/api/TimestampedSet/{idDiscriminator}";

View File

@ -1,8 +1,9 @@
using DD.Persistence.Models; using Microsoft.AspNetCore.Mvc;
using DD.Persistence.Models;
using Refit; using Refit;
namespace DD.Persistence.Client.Clients.Interfaces.Refit; namespace DD.Persistence.Client.Clients.Interfaces.Refit;
public interface IRefitWitsDataClient : IRefitClient, IDisposable public interface IRefitWitsDataClient : IDisposable
{ {
private const string BaseRoute = "/api/witsData"; private const string BaseRoute = "/api/witsData";

View File

@ -10,9 +10,9 @@ public class SetpointClient : BaseClient, ISetpointClient
{ {
private readonly IRefitSetpointClient refitSetpointClient; private readonly IRefitSetpointClient refitSetpointClient;
public SetpointClient(IRefitClientFactory<IRefitSetpointClient> refitSetpointClientFactory, ILogger<SetpointClient> logger) : base(logger) public SetpointClient(IRefitSetpointClient refitSetpointClient, ILogger<SetpointClient> logger) : base(logger)
{ {
this.refitSetpointClient = refitSetpointClientFactory.Create(); this.refitSetpointClient = refitSetpointClient;
} }
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token) public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)

View File

@ -11,9 +11,9 @@ public class TechMessagesClient : BaseClient, ITechMessagesClient
{ {
private readonly IRefitTechMessagesClient refitTechMessagesClient; private readonly IRefitTechMessagesClient refitTechMessagesClient;
public TechMessagesClient(IRefitClientFactory<IRefitTechMessagesClient> refitTechMessagesClientFactory, ILogger<TechMessagesClient> logger) : base(logger) public TechMessagesClient(IRefitTechMessagesClient refitTechMessagesClient, ILogger<TechMessagesClient> logger) : base(logger)
{ {
this.refitTechMessagesClient = refitTechMessagesClientFactory.Create(); this.refitTechMessagesClient = refitTechMessagesClient;
} }
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token) public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)

View File

@ -5,13 +5,13 @@ using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Models; using DD.Persistence.Models;
namespace DD.Persistence.Client.Clients; namespace DD.Persistence.Client.Clients;
public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where TDto : class, ITimeSeriesAbstractDto public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where TDto : class, new()
{ {
private readonly IRefitTimeSeriesClient<TDto> timeSeriesClient; private readonly IRefitTimeSeriesClient<TDto> timeSeriesClient;
public TimeSeriesClient(IRefitClientFactory<IRefitTimeSeriesClient<TDto>> refitTechMessagesClientFactory, ILogger<TimeSeriesClient<TDto>> logger) : base(logger) public TimeSeriesClient(IRefitTimeSeriesClient<TDto> refitTechMessagesClient, ILogger<TimeSeriesClient<TDto>> logger) : base(logger)
{ {
this.timeSeriesClient = refitTechMessagesClientFactory.Create(); this.timeSeriesClient = refitTechMessagesClient;
} }
public async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token) public async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token)

View File

@ -9,9 +9,9 @@ public class TimestampedSetClient : BaseClient, ITimestampedSetClient
{ {
private readonly IRefitTimestampedSetClient refitTimestampedSetClient; private readonly IRefitTimestampedSetClient refitTimestampedSetClient;
public TimestampedSetClient(IRefitClientFactory<IRefitTimestampedSetClient> refitTimestampedSetClientFactory, ILogger<TimestampedSetClient> logger) : base(logger) public TimestampedSetClient(IRefitTimestampedSetClient refitTimestampedSetClient, ILogger<TimestampedSetClient> logger) : base(logger)
{ {
this.refitTimestampedSetClient = refitTimestampedSetClientFactory.Create(); this.refitTimestampedSetClient = refitTimestampedSetClient;
} }
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token) public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token)

View File

@ -9,9 +9,9 @@ public class WitsDataClient : BaseClient, IWitsDataClient
{ {
private readonly IRefitWitsDataClient refitWitsDataClient; private readonly IRefitWitsDataClient refitWitsDataClient;
public WitsDataClient(IRefitClientFactory<IRefitWitsDataClient> refitWitsDataClientFactory, ILogger<WitsDataClient> logger) : base(logger) public WitsDataClient(IRefitWitsDataClient refitWitsDataClient, ILogger<WitsDataClient> logger) : base(logger)
{ {
this.refitWitsDataClient = refitWitsDataClientFactory.Create(); this.refitWitsDataClient = refitWitsDataClient;
} }
public async Task<int> AddRange(IEnumerable<WitsDataDto> dtos, CancellationToken token) public async Task<int> AddRange(IEnumerable<WitsDataDto> dtos, CancellationToken token)

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
@ -9,13 +9,13 @@
<!--Генерация NuGet пакета при сборке--> <!--Генерация NuGet пакета при сборке-->
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<!--Наименование--> <!--Наименование-->
<Title>DD.Persistence.Client</Title> <Title>Persistence.Client</Title>
<!--Версия пакета--> <!--Версия пакета-->
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix> <VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
<!--Версия сборки--> <!--Версия сборки-->
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion> <AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
<!--Id пакета--> <!--Id пакета-->
<PackageId>DD.Persistence.Client</PackageId> <PackageId>Persistence.Client</PackageId>
<!--Автор--> <!--Автор-->
<Authors>Digital Drilling</Authors> <Authors>Digital Drilling</Authors>
@ -33,7 +33,7 @@
<!--Формат пакета с символами--> <!--Формат пакета с символами-->
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<!--Путь к пакету--> <!--Путь к пакету-->
<PackageOutputPath>C:\Projects\Nuget\Persistence\Client</PackageOutputPath> <PackageOutputPath>C:\Projects\Nuget</PackageOutputPath>
<!--Readme--> <!--Readme-->
<PackageReadmeFile>Readme.md</PackageReadmeFile> <PackageReadmeFile>Readme.md</PackageReadmeFile>
@ -49,16 +49,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" /> <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
<PackageReference Include="Refit" Version="8.0.0" /> <PackageReference Include="Refit" Version="8.0.0" />
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" /> <PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
<PackageReference Include="RestSharp" Version="112.1.0" /> <PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DD.Persistence.Models\DD.Persistence.Models.csproj" /> <ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,30 +0,0 @@
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Models;
using Microsoft.Extensions.DependencyInjection;
namespace DD.Persistence.Client;
/// <summary>
///
/// </summary>
public static class DependencyInjection
{
/// <summary>
///
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddPersistenceClients(this IServiceCollection services)
{
services.AddTransient(typeof(IRefitClientFactory<>), typeof(RefitClientFactory<>));
services.AddTransient<IChangeLogClient, ChangeLogClient>();
services.AddTransient<IDataSourceSystemClient, DataSourceSystemClient>();
services.AddTransient<ISetpointClient, SetpointClient>();
services.AddTransient<ITechMessagesClient, TechMessagesClient>();
services.AddTransient<ITimeSeriesClient<DataSaubDto>, TimeSeriesClient<DataSaubDto>>();
services.AddTransient<ITimestampedSetClient, TimestampedSetClient>();
services.AddTransient<IWitsDataClient, WitsDataClient>();
return services;
}
}

View File

@ -1,16 +0,0 @@
using DD.Persistence.Client.Clients.Interfaces.Refit;
namespace DD.Persistence.Client;
/// <summary>
/// Интерфейс для фабрики, которая создает refit-клиентов
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRefitClientFactory<T> where T : IRefitClient
{
/// <summary>
/// Создание refit-клиента
/// </summary>
/// <returns></returns>
public T Create();
}

View File

@ -0,0 +1,146 @@
using Microsoft.Extensions.Configuration;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Helpers;
using Refit;
using DD.Persistence.Factories;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
namespace DD.Persistence.Client
{
/// <summary>
/// Фабрика клиентов для доступа к Persistence - сервису
/// </summary>
public class PersistenceClientFactory
{
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
};
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
private readonly IServiceProvider provider;
private HttpClient httpClient;
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider provider, IConfiguration configuration)
{
this.provider = provider;
httpClient = httpClientFactory.CreateClient();
httpClient.Authorize(configuration);
}
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IAuthTokenFactory authTokenFactory, IServiceProvider provider, IConfiguration configuration)
{
this.provider = provider;
httpClient = httpClientFactory.CreateClient();
var token = authTokenFactory.GetToken();
httpClient.Authorize(token);
}
/// <summary>
/// Получить клиент для работы с уставками
/// </summary>
/// <returns></returns>
public ISetpointClient GetSetpointClient()
{
var logger = provider.GetRequiredService<ILogger<SetpointClient>>();
var restClient = RestService.For<IRefitSetpointClient>(httpClient, RefitSettings);
var client = new SetpointClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с технологическими сообщениями
/// </summary>
/// <returns></returns>
public ITechMessagesClient GetTechMessagesClient()
{
var logger = provider.GetRequiredService<ILogger<TechMessagesClient>>();
var restClient = RestService.For<IRefitTechMessagesClient>(httpClient, RefitSettings);
var client = new TechMessagesClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с временными данными
/// </summary>
/// <typeparam name="TDto"></typeparam>
/// <returns></returns>
public ITimeSeriesClient<TDto> GetTimeSeriesClient<TDto>()
where TDto : class, new()
{
var logger = provider.GetRequiredService<ILogger<TimeSeriesClient<TDto>>>();
var restClient = RestService.For<IRefitTimeSeriesClient<TDto>>(httpClient, RefitSettings);
var client = new TimeSeriesClient<TDto>(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с данными с отметкой времени
/// </summary>
/// <returns></returns>
public ITimestampedSetClient GetTimestampedSetClient()
{
var logger = provider.GetRequiredService<ILogger<TimestampedSetClient>>();
var restClient = RestService.For<IRefitTimestampedSetClient>(httpClient, RefitSettings);
var client = new TimestampedSetClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы с записями ChangeLog
/// </summary>
/// <returns></returns>
public IChangeLogClient GetChangeLogClient()
{
var logger = provider.GetRequiredService<ILogger<ChangeLogClient>>();
var restClient = RestService.For<IRefitChangeLogClient>(httpClient, RefitSettings);
var client = new ChangeLogClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы c параметрами Wits
/// </summary>
/// <returns></returns>
public IWitsDataClient GetWitsDataClient()
{
var logger = provider.GetRequiredService<ILogger<WitsDataClient>>();
var restClient = RestService.For<IRefitWitsDataClient>(httpClient, RefitSettings);
var client = new WitsDataClient(restClient, logger);
return client;
}
/// <summary>
/// Получить клиент для работы c системами
/// </summary>
/// <returns></returns>
public IDataSourceSystemClient GetDataSourceSystemClient()
{
var logger = provider.GetRequiredService<ILogger<DataSourceSystemClient>>();
var restClient = RestService.For<IRefitDataSourceSystemClient>(httpClient, RefitSettings);
var client = new DataSourceSystemClient(restClient, logger);
return client;
}
}
}

View File

@ -1,52 +0,0 @@
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Helpers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Refit;
using System.Configuration;
using System.Text.Json;
namespace DD.Persistence.Client;
/// <summary>
/// Фабрика, которая создает refit-клиентов
/// </summary>
/// <typeparam name="T"></typeparam>
public class RefitClientFactory<T> : IRefitClientFactory<T> where T : IRefitClient
{
private HttpClient client;
private RefitSettings refitSettings;
/// <inheritdoc/>
public RefitClientFactory(IConfiguration configuration, ILogger<IRefitClientFactory<T>> logger, HttpClient client)
{
//this.client = factory.CreateClient();
this.client = client;
var baseUrl = configuration.GetSection("ClientUrl").Get<string>();
if (String.IsNullOrEmpty(baseUrl))
{
var exception = new SettingsPropertyNotFoundException("В настройках конфигурации не указан адрес Persistence сервиса.");
logger.LogError(exception.Message);
throw exception;
}
client.BaseAddress = new Uri(baseUrl);
JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
};
refitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
}
/// <summary>
/// создание клиента
/// </summary>
/// <returns></returns>
public T Create()
{
return RestService.For<T>(client, refitSettings);
}
}

View File

@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -0,0 +1,56 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DD.Persistence.Database.Entity;
public interface ITimestamped
{
DateTimeOffset Timestamp { get; set; }
}
[PrimaryKey(nameof(ParameterId), nameof(Timestamp))]
public class TagValue: ITimestamped
{
[Comment("Id параметра")]
public int ParameterId { get; set; }
[Comment("Временная отметка")]
public DateTimeOffset Timestamp { get; set; }
[Comment("Значение параметра")]
public float Value { get; set; }
}
public class TagSetValue: ITimestamped
{
[Comment("Временная отметка"), Key]
public DateTimeOffset Timestamp { get; set; }
public float WellDepth {get;set;}
public float BitDepth {get;set;}
public float BlockPosition {get;set;}
public float BlockSpeed {get;set;}
public float Pressure {get;set;}
public float AxialLoad {get;set;}
public float HookWeight {get;set;}
public float RotorTorque {get;set;}
public float RotorSpeed {get;set;}
public float Flow {get;set;}
public int Mse {get;set;}
public int Mode {get;set;}
public float Pump0Flow {get;set;}
public float Pump1Flow {get;set;}
public float Pump2Flow { get; set; }
}
[PrimaryKey(nameof(BagId), nameof(Timestamp))]
public class TagBag : ITimestamped
{
[Comment("Временная отметка"), Key]
public DateTimeOffset Timestamp { get; set; }
public Guid BagId { get; set; }
[Column(TypeName = "jsonb")]
public object[] Values { get; set; }
}

View File

@ -11,6 +11,10 @@ public class PersistenceDbContext : DbContext
{ {
public DbSet<DataSaub> DataSaub => Set<DataSaub>(); public DbSet<DataSaub> DataSaub => Set<DataSaub>();
public DbSet<TagValue> TagValues => Set<TagValue>();
public DbSet<TagSetValue> TagSetValues => Set<TagSetValue>();
public DbSet<TagBag> TagBag => Set<TagBag>();
public DbSet<Setpoint> Setpoint => Set<Setpoint>(); public DbSet<Setpoint> Setpoint => Set<Setpoint>();
public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>(); public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>();
@ -38,5 +42,9 @@ public class PersistenceDbContext : DbContext
modelBuilder.Entity<ChangeLog>() modelBuilder.Entity<ChangeLog>()
.Property(e => e.Value) .Property(e => e.Value)
.HasJsonConversion(); .HasJsonConversion();
modelBuilder.Entity<TagBag>()
.Property(e => e.Values)
.HasJsonConversion();
} }
} }

View File

@ -7,11 +7,6 @@ using DD.Persistence.Models.Requests;
using Xunit; using Xunit;
using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client; using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Clients;
using Microsoft.Extensions.Logging;
using Refit;
using System.Net.Http;
namespace DD.Persistence.IntegrationTests.Controllers; namespace DD.Persistence.IntegrationTests.Controllers;
public class ChangeLogControllerTest : BaseIntegrationTest public class ChangeLogControllerTest : BaseIntegrationTest
@ -21,12 +16,10 @@ public class ChangeLogControllerTest : BaseIntegrationTest
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory) public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
var refitClientFactory = scope.ServiceProvider var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitChangeLogClient>>(); .GetRequiredService<PersistenceClientFactory>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<ChangeLogClient>>();
client = scope.ServiceProvider client = persistenceClientFactory.GetChangeLogClient();
.GetRequiredService<IChangeLogClient>();
} }
[Fact] [Fact]

View File

@ -6,8 +6,6 @@ using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Database.Entity; using DD.Persistence.Database.Entity;
using DD.Persistence.Models; using DD.Persistence.Models;
using Xunit; using Xunit;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using Microsoft.Extensions.Logging;
namespace DD.Persistence.IntegrationTests.Controllers namespace DD.Persistence.IntegrationTests.Controllers
{ {
@ -18,12 +16,11 @@ namespace DD.Persistence.IntegrationTests.Controllers
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
public DataSourceSystemControllerTest(WebAppFactoryFixture factory) : base(factory) public DataSourceSystemControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
var refitClientFactory = scope.ServiceProvider var scope = factory.Services.CreateScope();
.GetRequiredService<IRefitClientFactory<IRefitDataSourceSystemClient>>(); var persistenceClientFactory = scope.ServiceProvider
var logger = scope.ServiceProvider.GetRequiredService<ILogger<DataSourceSystemClient>>(); .GetRequiredService<PersistenceClientFactory>();
dataSourceSystemClient = scope.ServiceProvider dataSourceSystemClient = persistenceClientFactory.GetDataSourceSystemClient();
.GetRequiredService<IDataSourceSystemClient>();
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>(); memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
} }

View File

@ -4,9 +4,6 @@ using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Database.Model; using DD.Persistence.Database.Model;
using System.Net; using System.Net;
using Xunit; using Xunit;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Clients;
using Microsoft.Extensions.Logging;
namespace DD.Persistence.IntegrationTests.Controllers namespace DD.Persistence.IntegrationTests.Controllers
{ {
@ -20,12 +17,11 @@ namespace DD.Persistence.IntegrationTests.Controllers
} }
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory) public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
var refitClientFactory = scope.ServiceProvider var scope = factory.Services.CreateScope();
.GetRequiredService<IRefitClientFactory<IRefitSetpointClient>>(); var persistenceClientFactory = scope.ServiceProvider
var logger = scope.ServiceProvider.GetRequiredService<ILogger<SetpointClient>>(); .GetRequiredService<PersistenceClientFactory>();
setpointClient = scope.ServiceProvider setpointClient = persistenceClientFactory.GetSetpointClient();
.GetRequiredService<ISetpointClient>();
} }
[Fact] [Fact]

View File

@ -1,14 +1,12 @@
using DD.Persistence.Client; using Microsoft.Extensions.Caching.Memory;
using DD.Persistence.Client.Clients; using Microsoft.Extensions.DependencyInjection;
using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Database.Entity; using DD.Persistence.Database.Entity;
using DD.Persistence.Models; using DD.Persistence.Models;
using DD.Persistence.Models.Enumerations; using DD.Persistence.Models.Enumerations;
using DD.Persistence.Models.Requests; using DD.Persistence.Models.Requests;
using Microsoft.Extensions.Caching.Memory; using System.Net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace DD.Persistence.IntegrationTests.Controllers namespace DD.Persistence.IntegrationTests.Controllers
@ -20,12 +18,11 @@ namespace DD.Persistence.IntegrationTests.Controllers
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory) public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
var refitClientFactory = scope.ServiceProvider var scope = factory.Services.CreateScope();
.GetRequiredService<IRefitClientFactory<IRefitTechMessagesClient>>(); var persistenceClientFactory = scope.ServiceProvider
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TechMessagesClient>>(); .GetRequiredService<PersistenceClientFactory>();
techMessagesClient = scope.ServiceProvider techMessagesClient = persistenceClientFactory.GetTechMessagesClient();
.GetRequiredService<ITechMessagesClient>();
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>(); memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
} }

View File

@ -1,19 +1,16 @@
using DD.Persistence.Client;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Database.Model;
using DD.Persistence.Models;
using Mapster; using Mapster;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Database.Model;
using System.Net;
using Xunit; using Xunit;
namespace DD.Persistence.IntegrationTests.Controllers; namespace DD.Persistence.IntegrationTests.Controllers;
public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrationTest public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrationTest
where TEntity : class, ITimestampedData, new() where TEntity : class, ITimestampedData, new()
where TDto : class, ITimeSeriesAbstractDto, new() where TDto : class, new()
{ {
private readonly ITimeSeriesClient<TDto> timeSeriesClient; private readonly ITimeSeriesClient<TDto> timeSeriesClient;
@ -21,12 +18,11 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
{ {
dbContext.CleanupDbSet<TEntity>(); dbContext.CleanupDbSet<TEntity>();
var refitClientFactory = scope.ServiceProvider var scope = factory.Services.CreateScope();
.GetRequiredService<IRefitClientFactory<IRefitTimeSeriesClient<TDto>>>(); var persistenceClientFactory = scope.ServiceProvider
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TimeSeriesClient<TDto>>>(); .GetRequiredService<PersistenceClientFactory>();
timeSeriesClient = scope.ServiceProvider timeSeriesClient = persistenceClientFactory.GetTimeSeriesClient<TDto>();
.GetRequiredService<ITimeSeriesClient<TDto>>();
} }
public async Task InsertRangeSuccess(TDto dto) public async Task InsertRangeSuccess(TDto dto)

View File

@ -3,9 +3,6 @@ using DD.Persistence.Client;
using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Models; using DD.Persistence.Models;
using Xunit; using Xunit;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Client.Clients;
using Microsoft.Extensions.Logging;
namespace DD.Persistence.IntegrationTests.Controllers; namespace DD.Persistence.IntegrationTests.Controllers;
public class TimestampedSetControllerTest : BaseIntegrationTest public class TimestampedSetControllerTest : BaseIntegrationTest
@ -14,12 +11,10 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
public TimestampedSetControllerTest(WebAppFactoryFixture factory) : base(factory) public TimestampedSetControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
var refitClientFactory = scope.ServiceProvider var persistenceClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitTimestampedSetClient>>(); .GetRequiredService<PersistenceClientFactory>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TimestampedSetClient>>();
client = scope.ServiceProvider client = persistenceClientFactory.GetTimestampedSetClient();
.GetRequiredService<ITimestampedSetClient>();
} }
[Fact] [Fact]

View File

@ -1,12 +1,10 @@
using DD.Persistence.Client; using Microsoft.Extensions.DependencyInjection;
using DD.Persistence.Client.Clients;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client.Clients.Interfaces.Refit;
using DD.Persistence.Database.Entity; using DD.Persistence.Database.Entity;
using DD.Persistence.Models; using DD.Persistence.Models;
using Microsoft.Extensions.DependencyInjection; using System.Net;
using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
using DD.Persistence.Client.Clients.Interfaces;
using DD.Persistence.Client;
namespace DD.Persistence.IntegrationTests.Controllers; namespace DD.Persistence.IntegrationTests.Controllers;
public class WitsDataControllerTest : BaseIntegrationTest public class WitsDataControllerTest : BaseIntegrationTest
@ -15,12 +13,11 @@ public class WitsDataControllerTest : BaseIntegrationTest
public WitsDataControllerTest(WebAppFactoryFixture factory) : base(factory) public WitsDataControllerTest(WebAppFactoryFixture factory) : base(factory)
{ {
var refitClientFactory = scope.ServiceProvider var scope = factory.Services.CreateScope();
.GetRequiredService<IRefitClientFactory<IRefitWitsDataClient>>(); var persistenceClientFactory = scope.ServiceProvider
var logger = scope.ServiceProvider.GetRequiredService<ILogger<WitsDataClient>>(); .GetRequiredService<PersistenceClientFactory>();
witsDataClient = scope.ServiceProvider witsDataClient = persistenceClientFactory.GetWitsDataClient();
.GetRequiredService<IWitsDataClient>();
} }
[Fact] [Fact]

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@ -10,17 +10,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.0" />
<PrivateAssets>all</PrivateAssets> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.10" />
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Refit" Version="8.0.0" /> <PackageReference Include="Refit" Version="8.0.0" />
<PackageReference Include="RestSharp" Version="112.1.0" /> <PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="xunit" Version="2.9.2" /> <PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.0"> <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,7 +1,4 @@
using DD.Persistence.Client.Helpers; namespace DD.Persistence.IntegrationTests
using Microsoft.Extensions.Configuration;
namespace DD.Persistence.IntegrationTests
{ {
/// <summary> /// <summary>
/// Фабрика HTTP клиентов для интеграционных тестов /// Фабрика HTTP клиентов для интеграционных тестов
@ -9,19 +6,14 @@ namespace DD.Persistence.IntegrationTests
public class TestHttpClientFactory : IHttpClientFactory public class TestHttpClientFactory : IHttpClientFactory
{ {
private readonly WebAppFactoryFixture factory; private readonly WebAppFactoryFixture factory;
private readonly IConfiguration configuration;
public TestHttpClientFactory(WebAppFactoryFixture factory, IConfiguration configuration) public TestHttpClientFactory(WebAppFactoryFixture factory)
{ {
this.factory = factory; this.factory = factory;
this.configuration = configuration;
} }
public HttpClient CreateClient(string name) public HttpClient CreateClient(string name)
{ {
var client = factory.CreateClient(); return factory.CreateClient();
client.Authorize(configuration);
return client;
} }
} }
} }

View File

@ -11,9 +11,6 @@ using DD.Persistence.Database.Model;
using DD.Persistence.Database.Postgres; using DD.Persistence.Database.Postgres;
using RestSharp; using RestSharp;
using DD.Persistence.App; using DD.Persistence.App;
using DD.Persistence.Client.Helpers;
using DD.Persistence.Factories;
using System.Net;
namespace DD.Persistence.IntegrationTests; namespace DD.Persistence.IntegrationTests;
public class WebAppFactoryFixture : WebApplicationFactory<Program> public class WebAppFactoryFixture : WebApplicationFactory<Program>
@ -43,12 +40,12 @@ public class WebAppFactoryFixture : WebApplicationFactory<Program>
services.AddLogging(builder => builder.AddConsole()); services.AddLogging(builder => builder.AddConsole());
services.RemoveAll<IHttpClientFactory>(); services.RemoveAll<IHttpClientFactory>();
services.AddSingleton<IHttpClientFactory>((provider) => services.AddSingleton<IHttpClientFactory>(provider =>
{ {
return new TestHttpClientFactory(this, provider.GetRequiredService<IConfiguration>()); return new TestHttpClientFactory(this);
}); });
services.AddHttpClient();
services.AddPersistenceClients(); services.AddSingleton<PersistenceClientFactory>();
var serviceProvider = services.BuildServiceProvider(); var serviceProvider = services.BuildServiceProvider();

View File

@ -1,43 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--Генерация NuGet пакета при сборке-->
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<!--Наименование-->
<Title>DD.Persistence.Models</Title>
<!--Версия пакета-->
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
<!--Версия сборки-->
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
<!--Id пакета-->
<PackageId>DD.Persistence.Models</PackageId>
<!--Автор-->
<Authors>Digital Drilling</Authors>
<!--Компания-->
<Company>Digital Drilling</Company>
<!--Описание-->
<Description>Пакет для получения dtos для работы с Persistence сервисом</Description>
<!--Url репозитория-->
<RepositoryUrl>https://git.ddrilling.ru/on.nemtina/persistence.git</RepositoryUrl>
<!--тип репозитория-->
<RepositoryType>git</RepositoryType>
<!--Символы отладки-->
<IncludeSymbols>true</IncludeSymbols>
<!--Формат пакета с символами-->
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<!--Путь к пакету-->
<PackageOutputPath>C:\Projects\Nuget\Persistence\Models</PackageOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View File

@ -91,7 +91,6 @@ namespace DD.Persistence.Repository.Repositories
await CreateSystemIfNotExist(systemId, token); await CreateSystemIfNotExist(systemId, token);
entity.SystemId = systemId; entity.SystemId = systemId;
entity.Timestamp = dto.Timestamp.ToUniversalTime();
entities.Add(entity); entities.Add(entity);
} }

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartupObject>DD.Persistence.TestTelemetryStress.Program_v2</StartupObject>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Program_v1.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Program_v1.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,267 @@

using DD.Persistence.Database.Entity;
using Microsoft.EntityFrameworkCore;
using Npgsql.Internal;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Intrinsics.X86;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace DD.Persistence.TestTelemetryStress;
internal class Program_v1
{
record TestDataItem(TagValue[] TagValues, TagSetValue[] TagSetValue);
enum Table { TagValue, TagSetValue }
enum Action { insert, select }
record Log(
Table Table,
Action Action,
DateTimeOffset Timestamp,
TimeSpan TimeSpan,
int tableLength,
int count);
static Random random = new Random((int)(DateTimeOffset.UtcNow.Ticks % 0x7FFFFFFF));
static void Main(string[] args)
{
/* Цель теста сравнить время отклика БД с телеметрией за все бурение
* по 2м схемам хранения:
* - TagSetValue - строка таблицы БД - 14 значений с одной отметкой времени.
* - TagValue - строка таблицы БД - 1 значение с отметкой времени и id параметра, для записи одной телеметрии используется 14 строк.
* Данные генерируются одинаковые и за все бурение - 30 дней *24 часа * 60 минут * 60 сек
*
* Вставка производится порциями по 56_000 записей для TagValue и по 4000 (56к/14) для TagSetValue.
* Замеряется время каждой вставки для построения графика. Таблицы вставки чередуются.
*
* После вставки контекст уничтожается и делается пауза
*
* Создается новые контексты для тестирования каждой выборки по каждой таблице по отдельности.
* Параметры выборок для тестирования:
* - 10 раз за произвольные 10 минут, интервалы распределены по всему диапазону дат
* - 10 раз за произвольные 60 минут, интервалы распределены по всему диапазону дат
* - 10 раз за произвольные 24*60 минут, интервалы распределены по всему диапазону дат
*/
var insertLogs = FillDB();
Pause();
var selectLogs = TestSelect();
var logs = insertLogs.Union(selectLogs);
ExportLogs(logs);
/* Анализ логов:
* - не замечено замедление вставки при увеличении размера таблиц
* - размер таблиц в БД TagValue - 1200Мб TagSetValue - 119Мб. В 10 раз больше
* - время вставки чанка TagValue в 7.3 раза больше времени вставки чанка TagSetValue
* - время выборки из TagValue в 16,4 раза больше времени выборки из TagSetValue
*/
}
private static void ExportLogs(IEnumerable<Log> logs)
{
using var stream = File.CreateText("log.csv");
foreach (Log log in logs)
{
stream.WriteLine($"{log.Table}, {log.Action}, {log.Timestamp}, {log.TimeSpan}, {log.count}, {log.tableLength}");
}
}
private static Log[] FillDB()
{
var begin = DateTimeOffset.UtcNow;
var increment = TimeSpan.FromSeconds(1);
var count = 30 * 24 * 60 * 60;
var data = GenerateData(count, begin, increment);
using var db = GetDb();
var tagValueSet = db.Set<TagValue>();
var tagSetValueSet = db.Set<TagSetValue>();
var tagValueInsertedCount = 0;
var tagSetValueInsertedCount = 0;
var logs = new List<Log>(data.Length * 2);
for (var i = 0; i < data.Length; i++)
{
var chunk = data[i];
var inserted = 0;
var stopwatch = Stopwatch.StartNew();
tagSetValueSet.AddRange(chunk.TagSetValue);
inserted = db.SaveChanges();
logs.Add(new Log(Table.TagSetValue, Action.insert, DateTimeOffset.UtcNow, stopwatch.Elapsed, tagSetValueInsertedCount, count));
tagValueInsertedCount += inserted;
db.ChangeTracker.Clear();
stopwatch.Restart();
tagValueSet.AddRange(chunk.TagValues);
inserted = db.SaveChanges();
logs.Add(new Log(Table.TagValue, Action.insert, DateTimeOffset.UtcNow, stopwatch.Elapsed, tagValueInsertedCount, count));
tagSetValueInsertedCount += inserted;
db.ChangeTracker.Clear();
}
return logs.ToArray();
}
private static void Pause()
{
Thread.Sleep(1000);
}
private static Log[] TestSelect()
{
var testDateRanges = GetTestDateRanges();
var logs1 = TestSelect<TagSetValue>(Table.TagSetValue, testDateRanges);
var logs2 = TestSelect<TagValue>(Table.TagValue, testDateRanges);
return [.. logs1, .. logs2];
}
private static Log[] TestSelect<T>(Table table, (DateTimeOffset begin, DateTimeOffset end)[] ranges)
where T : class, ITimestamped
{
using var db = GetDb();
var dbSet = db.Set<T>();
var totalCount = dbSet.Count();
var logs = new List<Log>(ranges.Length);
foreach (var range in ranges)
{
var stopwatch = Stopwatch.StartNew();
var selected = dbSet
.Where(e => e.Timestamp > range.begin)
.Where(e => e.Timestamp < range.end)
.ToArray();
logs.Add(new(table, Action.select, DateTimeOffset.UtcNow, stopwatch.Elapsed, totalCount, selected.Length));
}
return logs.ToArray();
}
private static (DateTimeOffset begin, DateTimeOffset end)[] GetTestDateRanges()
{
using var db = GetDb();
var dbSet1 = db.Set<TagSetValue>();
var min1 = dbSet1.Min(e => e.Timestamp);
var max1 = dbSet1.Max(e => e.Timestamp);
var dbSet2 = db.Set<TagValue>();
var min2 = dbSet2.Min(e => e.Timestamp);
var max2 = dbSet2.Max(e => e.Timestamp);
var min = min1 < min2 ? min1 : min2;
var max = max1 < max2 ? max2 : max1;
var list1 = CalculateRanges(min, max, TimeSpan.FromMinutes(10), 10);
var list2 = CalculateRanges(min, max, TimeSpan.FromMinutes(60), 10);
var list3 = CalculateRanges(min, max, TimeSpan.FromMinutes(24 * 60), 10);
return [..list1, ..list2, ..list3];
}
private static (DateTimeOffset begin, DateTimeOffset end)[] CalculateRanges(DateTimeOffset min, DateTimeOffset max, TimeSpan range, int count)
{
if (max - min < range)
throw new ArgumentException("max - min < range", nameof(range));
var result = new (DateTimeOffset begin, DateTimeOffset end)[count];
var max1 = max - range;
var delta = max1 - min;
var step = delta / count;
for (var i = 0; i < count; i++)
{
var b = min + i * step;
var e = b + step;
result[i] = (b, e);
}
return result;
}
private static DbContext GetDb()
{
var factory = new Database.Postgres.DesignTimeDbContextFactory();
var context = factory.CreateDbContext(Array.Empty<string>());
context.Database.EnsureCreated();
return context;
}
private static TestDataItem[] GenerateData(int count, DateTimeOffset begin, TimeSpan increment)
{
var chunkLimit = 4000;
var chunks = new List<TestDataItem>((count + chunkLimit) / chunkLimit);
for (int i = 0; i < count; i += chunkLimit)
{
var item = GenerateDataChunk(begin, increment, chunkLimit);
chunks.Add(item);
begin += increment * chunkLimit;
}
return chunks.ToArray();
}
private static TestDataItem GenerateDataChunk(DateTimeOffset begin, TimeSpan increment, int chunkLimit)
{
List<TagValue> tagValues = [];
List<TagSetValue> tagSetValue = [];
for (int i = 0; i < chunkLimit; i++)
{
var tagSet = GenerateTagSetValue(begin);
tagSetValue.Add(tagSet);
var items = MakeTagValues(tagSet);
tagValues.AddRange(items);
begin += increment;
}
return new(tagValues.ToArray(), tagSetValue.ToArray());
}
private static TagSetValue GenerateTagSetValue(DateTimeOffset begin)
{
var result = new TagSetValue
{
Timestamp = begin,
WellDepth = 100f * random.NextSingle(),
BitDepth = 100f * random.NextSingle(),
BlockPosition = 100f * random.NextSingle(),
BlockSpeed = 100f * random.NextSingle(),
Pressure = 100f * random.NextSingle(),
AxialLoad = 100f * random.NextSingle(),
HookWeight = 100f * random.NextSingle(),
RotorTorque = 100f * random.NextSingle(),
RotorSpeed = 100f * random.NextSingle(),
Flow = 100f * random.NextSingle(),
Mse = 100f * random.NextSingle(),
Pump0Flow = 100f * random.NextSingle(),
Pump1Flow = 100f * random.NextSingle(),
Pump2Flow = 100f * random.NextSingle(),
};
return result;
}
private static TagValue[] MakeTagValues(TagSetValue tagSet)
{
TagValue[] data =
[
new (){ Timestamp = tagSet.Timestamp, ParameterId = 1, Value = tagSet.WellDepth},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 2, Value = tagSet.BitDepth},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 3, Value = tagSet.BlockPosition},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 4, Value = tagSet.BlockSpeed},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 5, Value = tagSet.Pressure},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 6, Value = tagSet.AxialLoad},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 7, Value = tagSet.HookWeight},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 8, Value = tagSet.RotorTorque},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 9, Value = tagSet.RotorSpeed},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 10, Value = tagSet.Flow},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 11, Value = tagSet.Mse},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 12, Value = tagSet.Pump0Flow},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 13, Value = tagSet.Pump1Flow},
new (){ Timestamp = tagSet.Timestamp, ParameterId = 14, Value = tagSet.Pump2Flow},
];
return data;
}
}

View File

@ -0,0 +1,354 @@
using DD.Persistence.Database.Entity;
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using System.IO;
namespace DD.Persistence.TestTelemetryStress;
internal class Program_v2
{
record TestDataItem(TagBag[] TagBags, TagSetValue[] TagSetValue);
enum Table { TagBag, TagSetValue }
enum Action { insert, select }
record Log(
Table Table,
Action Action,
DateTimeOffset Timestamp,
TimeSpan TimeSpan,
int tableLength,
int count);
static Random random = new Random((int)(DateTimeOffset.UtcNow.Ticks % 0x7FFFFFFF));
static void Main(string[] args)
{
/* Цель теста сравнить время отклика БД с телеметрией за все бурение
* по 2м схемам хранения:
* - TagSetValue - строка таблицы БД - 14 значений с одной отметкой времени.
* - TagBag - строка таблицы БД - 1 значение с отметкой времени и id параметра, для записи одной телеметрии используется 14 строк.
* Данные генерируются одинаковые и за все бурение - 30 дней *24 часа * 60 минут * 60 сек
*
* Вставка производится порциями по 172_800 записей (2 дня)
* Замеряется время каждой вставки для построения графика. Таблицы вставки чередуются.
*
* После вставки контекст уничтожается и делается пауза
*
* Создается новые контексты для тестирования каждой выборки по каждой таблице по отдельности.
* Параметры выборок для тестирования:
* - 10 раз за произвольные 10 минут, интервалы распределены по всему диапазону дат
* - 10 раз за произвольные 60 минут, интервалы распределены по всему диапазону дат
* - 10 раз за произвольные 24*60 минут, интервалы распределены по всему диапазону дат
*/
var begin = DateTimeOffset.Now;
Console.WriteLine($"Started at {begin}");
var insertLogs = FillDB();
Pause();
var selectLogs = TestSelect();
var logs = insertLogs.Union(selectLogs);
var end = DateTimeOffset.Now;
Console.WriteLine($"complete at {end}, estimate {end - begin}");
AnalyzeAndExportLogs(logs);
/* Анализ логов:
* - не замечено замедление вставки при увеличении размера таблиц 2592000 записей
* - размер таблиц в БД TagBag - 778Мб TagSetValue - 285Мб. В 2,73 раз больше
* - время вставки всех чанков TagBag - 2м11с, TagSetValue - 3м40с
* - время выборки из TagBag 21.69c (256180 записей) на 65% медленнее времени выборки из TagSetValue 13,11с (256180 записей)
* Вывод: приемлемо
*/
}
private static void AnalyzeAndExportLogs(IEnumerable<Log> logs)
{
var orderedLogs = logs
.OrderBy(l => l.Action)
.ThenBy(l => l.Table)
.ThenBy(l => l.Timestamp);
var groups = orderedLogs
.GroupBy(log => new { log.Action , log.Table })
.OrderBy(group => group.Key.Action)
.ThenBy(group => group.Key.Table);
using var analysisStream = File.CreateText($"Analysis_{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.csv");
analysisStream.WriteLine("{Table}, {Action}, Sum(Time), Sum(Count), Max(TableLength)");
foreach (var group in groups)
{
var max = group.Max(i => i.tableLength);
var count = group.Sum(i => i.count);
var timeMs = group.Sum(i => i.TimeSpan.TotalMilliseconds);
var time = TimeSpan.FromMilliseconds(timeMs);
var line = $"{group.Key.Table}, {group.Key.Action}, {time}, {count}, {max}";
analysisStream.WriteLine(line);
}
analysisStream.WriteLine(string.Empty);
analysisStream.WriteLine("{Table}, {Action}, Avg(Time), Avg(Count), Max(TableLength)");
foreach (var group in groups.Where(g => g.Key.Action == Action.select))
{
var subGroups = group.GroupBy(i => Math.Round( 0.01d * i.count));
foreach (var subGroup in subGroups)
{
var max = subGroup.Max(i => i.tableLength);
var count = subGroup.Average(i => i.count);
var timeMs = subGroup.Average(i => i.TimeSpan.TotalMilliseconds);
var time = TimeSpan.FromMilliseconds(timeMs);
var line = $"{group.Key.Table}, {group.Key.Action}, {time}, {count}, {max}";
analysisStream.WriteLine(line);
}
}
analysisStream.WriteLine(string.Empty);
analysisStream.WriteLine("Table, Action, Time, Count, TableLength");
foreach (var log in orderedLogs)
{
analysisStream.WriteLine($"{log.Table}, {log.Action}, {log.TimeSpan}, {log.count}, {log.tableLength}");
}
}
private static Log[] FillDB()
{
var begin = DateTimeOffset.UtcNow;
var increment = TimeSpan.FromSeconds(1);
var count = 30 * 24 * 60 * 60;
var logStopwatch = Stopwatch.StartNew();
var data = GenerateData(count, begin, increment);
Console.WriteLine($"Data[{data.Length}] generated {logStopwatch.Elapsed}");
logStopwatch.Restart();
using var db = GetDb();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
Console.WriteLine($"Database recreated {logStopwatch.Elapsed}");
var tagBagSet = db.Set<TagBag>();
var tagSetValueSet = db.Set<TagSetValue>();
var tagBagInsertedCount = 0;
var tagSetValueInsertedCount = 0;
var logs = new List<Log>(data.Length * 2);
for (var i = 0; i < data.Length; i++)
{
var chunk = data[i];
var inserted = 0;
var stopwatch = Stopwatch.StartNew();
tagSetValueSet.AddRange(chunk.TagSetValue);
inserted = db.SaveChanges();
logs.Add(new Log(Table.TagSetValue, Action.insert, DateTimeOffset.UtcNow, stopwatch.Elapsed, tagBagInsertedCount, inserted));
tagBagInsertedCount += inserted;
db.ChangeTracker.Clear();
Console.WriteLine($"chunk {i} of {data.Length} TagSetValue[{chunk.TagSetValue.Length}] added {stopwatch.Elapsed}");
stopwatch.Restart();
tagBagSet.AddRange(chunk.TagBags);
inserted = db.SaveChanges();
logs.Add(new Log(Table.TagBag, Action.insert, DateTimeOffset.UtcNow, stopwatch.Elapsed, tagSetValueInsertedCount, inserted));
tagSetValueInsertedCount += inserted;
db.ChangeTracker.Clear();
Console.WriteLine($"chunk {i} of {data.Length} TagBags[{chunk.TagBags.Length}] added {stopwatch.Elapsed}");
}
return logs.ToArray();
}
private static void Pause()
{
GC.Collect();
Thread.Sleep(1000);
}
private static Log[] TestSelect()
{
var testDateRanges = GetTestDateRanges();
var logs1 = TestSelect<TagSetValue>(Table.TagSetValue, testDateRanges);
var logs2 = TestSelect<TagBag>(Table.TagBag, testDateRanges);
return [.. logs1, .. logs2];
}
private static Log[] TestSelect<T>(Table table, (DateTimeOffset begin, DateTimeOffset end)[] ranges)
where T : class, ITimestamped
{
using var db = GetDb();
var dbSet = db.Set<T>();
var totalCount = dbSet.Count();
var logs = new List<Log>(ranges.Length);
foreach (var range in ranges)
{
var stopwatch = Stopwatch.StartNew();
var selected = dbSet
.Where(e => e.Timestamp > range.begin)
.Where(e => e.Timestamp < range.end)
.ToArray();
var count = selected.Length;
var maxTime = selected.Max(e => e.Timestamp);
logs.Add(new Log(table, Action.select, DateTimeOffset.UtcNow, stopwatch.Elapsed, totalCount, count));
}
return logs.ToArray();
}
private static (DateTimeOffset begin, DateTimeOffset end)[] GetTestDateRanges()
{
using var db = GetDb();
var dbSet1 = db.Set<TagSetValue>();
var min1 = dbSet1.Min(e => e.Timestamp);
var max1 = dbSet1.Max(e => e.Timestamp);
var dbSet2 = db.Set<TagBag>();
var min2 = dbSet2.Min(e => e.Timestamp);
var max2 = dbSet2.Max(e => e.Timestamp);
var min = min1 < min2 ? min1 : min2;
var max = max1 > max2 ? max1 : max2;
var list1 = CalculateRanges(min, max, TimeSpan.FromMinutes(60), 10);
var list2 = CalculateRanges(min, max, TimeSpan.FromMinutes(12 * 60), 10);
var list3 = CalculateRanges(min, max, TimeSpan.FromMinutes(24 * 60), 10);
return [..list1, ..list2, ..list3];
}
private static (DateTimeOffset begin, DateTimeOffset end)[] CalculateRanges(DateTimeOffset min, DateTimeOffset max, TimeSpan range, int count)
{
if (max - min < range)
throw new ArgumentException("max - min < range", nameof(range));
var result = new (DateTimeOffset begin, DateTimeOffset end)[count];
var max1 = max - range;
var delta = max1 - min;
var step = delta / count;
for (var i = 0; i < count; i++)
{
var b = min + i * step;
var e = b + range;
result[i] = (b, e);
}
return result;
}
private static DbContext GetDb()
{
var factory = new Database.Postgres.DesignTimeDbContextFactory();
var context = factory.CreateDbContext(Array.Empty<string>());
return context;
}
private static TestDataItem[] GenerateData(int count, DateTimeOffset begin, TimeSpan increment)
{
var chunkLimit = 172_800;
var chunks = new List<TestDataItem>((count + chunkLimit) / chunkLimit);
for (int i = 0; i < count; i += chunkLimit)
{
var item = GenerateDataChunk(begin, increment, chunkLimit);
chunks.Add(item);
begin += increment * chunkLimit;
}
return chunks.ToArray();
}
private static TestDataItem GenerateDataChunk(DateTimeOffset begin, TimeSpan increment, int chunkLimit)
{
List<TagBag> tagBags = [];
List<TagSetValue> tagSetValue = [];
for (int i = 0; i < chunkLimit; i++)
{
var tagSet = GenerateTagSetValue(begin);
tagSetValue.Add(tagSet);
var tagBag = MakeTagBag(tagSet);
tagBags.Add(tagBag);
begin += increment;
}
return new(tagBags.ToArray(), tagSetValue.ToArray());
}
private static TagSetValue GenerateTagSetValue(DateTimeOffset begin)
{
var result = new TagSetValue
{
Timestamp = begin,
WellDepth = 100f * random.NextSingle(),
BitDepth = 100f * random.NextSingle(),
BlockPosition = 100f * random.NextSingle(),
BlockSpeed = 100f * random.NextSingle(),
Pressure = 100f * random.NextSingle(),
AxialLoad = 100f * random.NextSingle(),
HookWeight = 100f * random.NextSingle(),
RotorTorque = 100f * random.NextSingle(),
RotorSpeed = 100f * random.NextSingle(),
Flow = 100f * random.NextSingle(),
Mse = random.Next(),
Mode = random.Next(),
Pump0Flow = 100f * random.NextSingle(),
Pump1Flow = 100f * random.NextSingle(),
Pump2Flow = 100f * random.NextSingle(),
};
return result;
}
private static Guid BagId = Guid.NewGuid();
private static TagBag MakeTagBag(TagSetValue tagSet)
{
TagBag data = new()
{
BagId = BagId,
Timestamp = tagSet.Timestamp,
Values =
[
tagSet.WellDepth,
tagSet.BitDepth,
tagSet.BlockPosition,
tagSet.BlockSpeed,
tagSet.Pressure,
tagSet.AxialLoad,
tagSet.HookWeight,
tagSet.RotorTorque,
tagSet.RotorSpeed,
tagSet.Flow,
tagSet.Mse,
tagSet.Mode,
tagSet.Pump0Flow,
tagSet.Pump1Flow,
tagSet.Pump2Flow,
],
//new Dictionary<string, object>()
//{
// {"WellDepth", tagSet.WellDepth },
// {"BitDepth", tagSet.BitDepth},
// {"BlockPosition", tagSet.BlockPosition},
// {"BlockSpeed", tagSet.BlockSpeed},
// {"Pressure", tagSet.Pressure},
// {"AxialLoad", tagSet.AxialLoad},
// {"HookWeight", tagSet.HookWeight},
// {"RotorTorque", tagSet.RotorTorque},
// {"RotorSpeed", tagSet.RotorSpeed},
// {"Flow", tagSet.Flow},
// {"Mse", tagSet.Mse},
// {"Pump0Flow", tagSet.Pump0Flow},
// {"Pump1Flow", tagSet.Pump1Flow},
// {"Pump2Flow", tagSet.Pump2Flow},
//}
};
return data;
}
}

View File

@ -0,0 +1,26 @@
## Dictionary<string, object>
TagBag insert 00:02:31,55 2592000 2419200
TagSetValue insert 00:04:14,89 2592000 2419200
TagBag select 00:00:16,91 905997 2592000
TagSetValue select 00:00:02,42 905997 2592000
sizeof(TagBag) = 1200M
sizeof(TagSetValue) = 285M
Tot = 7m
## object[]
{Table} {Action} Sum(Time) Sum(Count) Max(TableLength)
TagBag insert 00:02:13,39 2592000 2419200
TagSetValue insert 00:03:57,70 2592000 2419200
TagBag select 00:00:12,60 1331997 2592000
TagSetValue select 00:00:02,88 1331997 2592000
sizeof(TagBag) = 805M
sizeof(TagSetValue) = 305M
## multi rows
размер таблиц в БД TagValue - 1200Мб TagSetValue - 119Мб. В 10 раз больше
время вставки чанка TagValue в 7.3 раза больше времени вставки чанка TagSetValue
время выборки из TagValue в 16,4 раза больше времени выборки из TagSetValue

View File

@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Client", "DD
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.App", "DD.Persistence.App\DD.Persistence.App.csproj", "{063238BF-E982-43FA-9DDB-7D7D279086D8}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.App", "DD.Persistence.App\DD.Persistence.App.csproj", "{063238BF-E982-43FA-9DDB-7D7D279086D8}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.Models", "DD.Persistence.Models\DD.Persistence.Models.csproj", "{698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DD.Persistence.TestTelemetryStress", "DD.Persistence.TestTelemetryStress\DD.Persistence.TestTelemetryStress.csproj", "{A75B3712-1E1D-4C5B-B97C-72C80E7D6BDE}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -59,10 +59,10 @@ Global
{063238BF-E982-43FA-9DDB-7D7D279086D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {063238BF-E982-43FA-9DDB-7D7D279086D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{063238BF-E982-43FA-9DDB-7D7D279086D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {063238BF-E982-43FA-9DDB-7D7D279086D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{063238BF-E982-43FA-9DDB-7D7D279086D8}.Release|Any CPU.Build.0 = Release|Any CPU {063238BF-E982-43FA-9DDB-7D7D279086D8}.Release|Any CPU.Build.0 = Release|Any CPU
{698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A75B3712-1E1D-4C5B-B97C-72C80E7D6BDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {A75B3712-1E1D-4C5B-B97C-72C80E7D6BDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {A75B3712-1E1D-4C5B-B97C-72C80E7D6BDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{698B4571-BB7A-4A42-8B0B-6C7F2F5360FB}.Release|Any CPU.Build.0 = Release|Any CPU {A75B3712-1E1D-4C5B-B97C-72C80E7D6BDE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
@ -17,11 +17,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
</ItemGroup> <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.2.1" />
<ItemGroup>
<ProjectReference Include="..\DD.Persistence.Models\DD.Persistence.Models.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -19,7 +19,6 @@ namespace DD.Persistence.Repositories
/// <summary> /// <summary>
/// Добавление новых сообщений /// Добавление новых сообщений
/// </summary> /// </summary>
/// <param name="systemId"></param>
/// <param name="dtos"></param> /// <param name="dtos"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>