Draft WellOperationImportService. incomplete

This commit is contained in:
Фролов 2021-10-08 17:00:30 +05:00
parent 674fe9586c
commit 2868304546
8 changed files with 193 additions and 32 deletions

View File

@ -31,7 +31,7 @@ namespace AsbCloudDb.Model
public virtual DbSet<UserRole> UserRoles { get; set; }
public virtual DbSet<Well> Wells { get; set; }
public virtual DbSet<WellOperation> WellOperations { get; set; }
public virtual DbSet<WellOperationCategory> TelemetryOperations { get; set; }
public virtual DbSet<WellOperationCategory> WellOperationCategories { get; set; }
public virtual DbSet<WellSectionType> WellSectionTypes { get; set; }
public virtual DbSet<WellType> WellTypes { get; set; }

View File

@ -23,7 +23,7 @@ namespace AsbCloudDb.Model
DbSet<FileCategory> FileCategories { get; set; }
DbSet<Telemetry> Telemetries { get; set; }
DbSet<TelemetryUser> TelemetryUsers { get; set; }
DbSet<WellOperationCategory> TelemetryOperations { get; set; }
DbSet<WellOperationCategory> WellOperationCategories { get; set; }
DbSet<TelemetryAnalysis> TelemetryAnalysis { get; set; }
DbSet<Well> Wells { get; set; }
DbSet<WellSectionType> WellSectionTypes { get; set; }

View File

@ -170,7 +170,7 @@ namespace AsbCloudInfrastructure.Services.Analysis
return await (from a in db.TelemetryAnalysis
where a.IdTelemetry == telemetryId &&
a.UnixDate > unixBegin && a.UnixDate < unixEnd
join o in db.TelemetryOperations on a.IdOperation equals o.Id
join o in db.WellOperationCategories on a.IdOperation equals o.Id
group a by new { a.IdOperation, o.Name } into g
select new TelemetryOperationDurationDto
{
@ -198,7 +198,7 @@ namespace AsbCloudInfrastructure.Services.Analysis
// Without dividing these operations duration by given interval
var ops = await (from a in db.TelemetryAnalysis
where a.IdTelemetry == telemetryId
join o in db.TelemetryOperations on a.IdOperation equals o.Id
join o in db.WellOperationCategories on a.IdOperation equals o.Id
group a by new
{
Interval = Math.Floor((a.UnixDate - workBeginSeconds + timezoneOffset) / intervalSeconds),

View File

@ -2,10 +2,9 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ClosedXML.Excel;
using AsbCloudApp.Data;
using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services
{
@ -14,24 +13,188 @@ namespace AsbCloudInfrastructure.Services
private const string sheetNamePlan = "План";
private const string sheetNameFact = "Факт";
private static readonly DateTime dateLimitMin = new DateTime(2001,1,1,0,0,0);
private static readonly DateTime dateLimitMax = new DateTime(2099,1,1,0,0,0);
private static readonly TimeSpan drillingDurationLimitMax = TimeSpan.FromDays(366);
private readonly IAsbCloudDbContext db;
private List<WellOperationCategory> categories = null;
public List<WellOperationCategory> Categories {
get {
if (categories is null)
categories = db.WellOperationCategories.ToList();
return categories;
}
}
private List<WellSectionType> sections = null;
public List<WellSectionType> Sections
{
get
{
if (sections is null)
sections = db.WellSectionTypes.ToList();
return sections;
}
}
public WellOperationImportService(IAsbCloudDbContext db)
{
this.db = db;
}
public IEnumerable<WellOperationDto> ParseFile(string excelFilePath)
{
if (!File.Exists(excelFilePath))
throw new FileNotFoundException($"Файл {excelFilePath} не найден.");
return ParseWorkbook(excelFilePath);
}
private IEnumerable<WellOperationDto> ParseWorkbook(string excelFilePath)
{
using var sourceExcelWorkbook = new XLWorkbook(excelFilePath, XLEventTracking.Disabled);
var sheetPlan = sourceExcelWorkbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlan);
if (sheetPlan is null)
throw new FileFormatException($"Файл {excelFilePath} не не содержит листа {sheetNamePlan}.");
var sheetFact = sourceExcelWorkbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameFact);
if (sheetFact is null)
throw new FileFormatException($"Файл {excelFilePath} не не содержит листа {sheetNameFact}.");
//sheetPlan.RangeUsed().RangeAddress.LastAddress.ColumnNumber
var wellOperations = new List<WellOperationDto>();
var wellOperationsPlan = ParseSheet(sheetPlan, 0);
wellOperations.AddRange(wellOperationsPlan);
var wellOperationsFact = ParseSheet(sheetFact, 1);
wellOperations.AddRange(wellOperationsFact);
return wellOperations;
}
private IEnumerable<WellOperationDto> ParseSheet(IXLWorksheet sheet, int idType)
{
const int headerRowsCount = 1;
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 7)
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцев.");
var count = sheet.RowsUsed().Count() - headerRowsCount;
if (count > 1024)
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество операций.");
if (count <= 0)
return new List<WellOperationDto>();
var operations = new List<WellOperationDto>(count);
var parseErrors = new List<string>();
DateTime lastOperationDateStart = new DateTime();
for (int i = 0; i < count; i++)
{
var row = sheet.Row(1 + i + headerRowsCount);
try
{
var operation = ParseRow(row, idType);
operations.Add(operation);
if (lastOperationDateStart > operation.DateStart)
parseErrors.Add($"Лист {sheet.Name} строка {row.RowNumber()} дата позднее даты предыдущей операции.");
lastOperationDateStart = operation.DateStart;
}
catch(FileFormatException ex)
{
parseErrors.Add(ex.Message);
}
};
// проверка диапазона дат
if(operations.Min(o => o.DateStart) - operations.Max(o => o.DateStart) > drillingDurationLimitMax)
parseErrors.Add($"Лист {sheet.Name} содержит диапазон дат больше {drillingDurationLimitMax}");
if (parseErrors.Any())
throw new FileFormatException(string.Join("\r\n", parseErrors));
return operations;
}
private WellOperationDto ParseRow(IXLRow row, int idType)
{
const int columnSection = 1;
const int columnCategory = 2;
const int columnCategoryInfo = 3;
const int columnDepthStart = 4;
const int columnDepthEnd = 5;
const int columnDate = 6;
const int columnDuration = 7;
const int columnComment = 8;
var vSection = row.Cell(columnSection).Value;
var vCategory = row.Cell(columnCategory).Value;
var vCategoryInfo = row.Cell(columnCategoryInfo).Value;
var vDepthStart = row.Cell(columnDepthStart).Value;
var vDepthEnd = row.Cell(columnDepthEnd).Value;
var vDate = row.Cell(columnDate).Value;
var vDuration = row.Cell(columnDuration).Value;
var vComment = row.Cell(columnComment).Value;
var operation = new WellOperationDto{IdType = idType};
if (vSection is string sectionName)
{
var section = Sections.Find(c => c.Caption.ToLower() == sectionName.ToLower());
if (section is null)
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} указана некорректная секция");
operation.IdWellSectionType = section.Id;
operation.WellSectionTypeName = section.Caption;
}
else
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана секция");
if (vCategory is string categoryName)
{
var category = Categories.Find(c => c.Name.ToLower() == categoryName.ToLower());
if(category is null)
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} указана некорректная операция");
operation.IdCategory = category.Id;
operation.CategoryName = category.Name;
}
else
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана операция");
if (vCategoryInfo is not null)
operation.CategoryInfo = vCategoryInfo.ToString();
if (vDepthStart is double depthStart && depthStart >= 0d && depthStart <= 20_000d)
operation.DepthStart = depthStart;
else
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана глубина на начало операции");
if (vDepthEnd is double depthEnd && depthEnd >= 0d && depthEnd <= 20_000d)
operation.DepthEnd = depthEnd;
else
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана глубина при завершении операции");
if (vDate is DateTime date && date > dateLimitMin && date < dateLimitMax)
operation.DateStart = date;
else
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} неправильно указана дата/время начала операции");
if (vDuration is double duration && duration >= 0d && duration <= 240d)
operation.DurationHours = duration;
else
throw new FileFormatException($"Лист {row.Worksheet.Name}. Строка {row.RowNumber()} не указана длительность операции");
if (vComment is not null)
operation.Comment = vComment.ToString();
return operation;
}
}
}

View File

@ -1,23 +1,23 @@
{
"files": {
"main.css": "/static/css/main.01936687.chunk.css",
"main.js": "/static/js/main.d2dfd398.chunk.js",
"main.js.map": "/static/js/main.d2dfd398.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.7bbed929.js",
"runtime-main.js.map": "/static/js/runtime-main.7bbed929.js.map",
"static/js/2.766da71c.chunk.js": "/static/js/2.766da71c.chunk.js",
"static/js/2.766da71c.chunk.js.map": "/static/js/2.766da71c.chunk.js.map",
"static/js/3.58b81d69.chunk.js": "/static/js/3.58b81d69.chunk.js",
"static/js/3.58b81d69.chunk.js.map": "/static/js/3.58b81d69.chunk.js.map",
"main.css": "/static/css/main.1a531ce4.chunk.css",
"main.js": "/static/js/main.d3cf7fb0.chunk.js",
"main.js.map": "/static/js/main.d3cf7fb0.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.b402d8a8.js",
"runtime-main.js.map": "/static/js/runtime-main.b402d8a8.js.map",
"static/js/2.f3289dc7.chunk.js": "/static/js/2.f3289dc7.chunk.js",
"static/js/2.f3289dc7.chunk.js.map": "/static/js/2.f3289dc7.chunk.js.map",
"static/js/3.a064d157.chunk.js": "/static/js/3.a064d157.chunk.js",
"static/js/3.a064d157.chunk.js.map": "/static/js/3.a064d157.chunk.js.map",
"index.html": "/index.html",
"static/css/main.01936687.chunk.css.map": "/static/css/main.01936687.chunk.css.map",
"static/js/2.766da71c.chunk.js.LICENSE.txt": "/static/js/2.766da71c.chunk.js.LICENSE.txt",
"static/css/main.1a531ce4.chunk.css.map": "/static/css/main.1a531ce4.chunk.css.map",
"static/js/2.f3289dc7.chunk.js.LICENSE.txt": "/static/js/2.f3289dc7.chunk.js.LICENSE.txt",
"static/media/pointer.e8df778c.svg": "/static/media/pointer.e8df778c.svg"
},
"entrypoints": [
"static/js/runtime-main.7bbed929.js",
"static/js/2.766da71c.chunk.js",
"static/css/main.01936687.chunk.css",
"static/js/main.d2dfd398.chunk.js"
"static/js/runtime-main.b402d8a8.js",
"static/js/2.f3289dc7.chunk.js",
"static/css/main.1a531ce4.chunk.css",
"static/js/main.d3cf7fb0.chunk.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="manifest" href="/manifest.json"/><title>АСБ Vision</title><link href="/static/css/main.01936687.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,a,i=r[0],c=r[1],l=r[2],s=0,p=[];s<i.length;s++)a=i[s],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&p.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var c=t[i];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{3:"58b81d69"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=this.webpackJsonpasb_cloud_front_react=this.webpackJsonpasb_cloud_front_react||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var f=c;t()}([])</script><script src="/static/js/2.766da71c.chunk.js"></script><script src="/static/js/main.d2dfd398.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="manifest" href="/manifest.json"/><title>АСБ Vision</title><link href="/static/css/main.1a531ce4.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,a,i=r[0],c=r[1],l=r[2],s=0,p=[];s<i.length;s++)a=i[s],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&p.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var c=t[i];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+"static/js/"+({}[e]||e)+"."+{3:"a064d157"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=this.webpackJsonpasb_cloud_front_react=this.webpackJsonpasb_cloud_front_react||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var f=c;t()}([])</script><script src="/static/js/2.f3289dc7.chunk.js"></script><script src="/static/js/main.d3cf7fb0.chunk.js"></script></body></html>

View File

@ -12,17 +12,15 @@ namespace ConsoleApp1
{
public static class DebugWellOperationImportService
{
private static DbContextOptions<AsbCloudDbContext> options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
.Options;
public static void Main(/*string[] args*/)
{
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
.Options;
using var db = new AsbCloudDbContext(options);
var cacheDb = new CacheDb();
var wellService = new WellService(db, new TelemetryTracker(), cacheDb);
var wellOperationImportService = new WellOperationImportService();
var wellOperationImportService = new WellOperationImportService(db);
var ops = wellOperationImportService.ParseFile(@"C:\temp\Миграция.xlsx");

View File

@ -9,7 +9,7 @@
{
static void Main(/*string[] args*/)
{
ActionWellOperationsRefactor.Main();
DebugWellOperationImportService.Main();
}
}
}