Академический Документы
Профессиональный Документы
Культура Документы
РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное государственное бюджетное образовательное учреждение
высшего образования
«Рязанский государственный радиотехнический университет имени В.Ф. Уткина»
«К защите»
Заведующий кафедрой ВПМ
Овечкин Г.В.
«10» июня 2021 г.
ВЫПУСКНАЯ КВАЛИФИКАЦИОННАЯ
РАБОТА
(бакалавриат)
на тему
Рязань 2021
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ
ФЕДЕРАЦИИ
ЗАДАНИЕ
на бакалаврскую выпускную квалификационную работу
2
1.7. Нормативные документы для проведения поверки
1.8. Гарантии достоверности результатов поверки
1.9. Калибровка средств измерения
2. Анализ технического задания
2.1. Анализ предметной области
2.2. Особенности разрабатываемого программного обеспечения
2.3. Анализ существующих разработок
2.4. Выбор модели данных
2.5. Выбор СУБД
3. Разработка программного обеспечения
3.1. Разработка библиотеки сервер
3.2. Разработка библиотеки доступа к базе данных
4. Разработка базы данных
5. Руководство пользователя
6. Описание рабочего места оператора
7. Тестирование системы
Заключение
Список использованных источников
Приложение А
Приложение Б
6. Перечень графического материала (с точным указанием обязательных чертежей)
Постановка задачи 1 лист
Структура данных 1 лист
3
РЕФЕРАТ
4
ANNOTATION
5
ОГЛАВЛЕНИЕ
РЕФЕРАТ.................................................................................................................4
ANNOTATION.........................................................................................................5
ОГЛАВЛЕНИЕ........................................................................................................6
ВВЕДЕНИЕ..............................................................................................................9
1. ТЕОРЕТИЧЕСКОЕ ОБОСНОВАНИЕ ТЕМЫ ПРОЕКТА..........................12
1.1. Понятие поверки....................................................................................12
1.2. Первичная поверка................................................................................13
1.3. Периодическая поверка.........................................................................15
1.4. Внеочередная поверка...........................................................................16
1.5. Инспекционная поверка........................................................................16
1.6. Экспертная поверка...............................................................................17
1.7. Нормативные документы для проведения поверки...........................17
1.8. Гарантии достоверности результатов поверки...................................18
1.9. Калибровка средств измерения............................................................19
2. АНАЛИЗ ТЕХНИЧЕСКОГО ЗАДАНИЯ.....................................................21
2.1. Анализ предметной области.................................................................21
2.2. Особенности разрабатываемого программного обеспечения...........22
2.3. Анализ существующих разработок......................................................24
2.3.1. ПАК MTE Calegration.........................................................................24
2.3.2. ПАК Pover1C.......................................................................................26
2.3.3. ПАК «Энергоформа»..........................................................................27
2.4. Выбор модели данных...........................................................................28
2.5. Выбор СУБД..........................................................................................29
3. РАЗРАБОТКА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ.................................30
3.1. Библиотека сервера...............................................................................30
3.1.1. Назначение и принцип работы библиотеки.....................................30
3.1.2. Обработчик запроса (DefaultHandler и RequestHandler).................31
3.1.3. Информация о URI.............................................................................33
6
3.1.4. Веб-сервер. Схема работы.................................................................34
3.1.5. Описание функции поиска реализации метода запроса.................35
3.1.6. Описание функции прослушивания входящих запросов...............38
3.1.7. Пример создания серверного приложения.......................................40
3.2. Библиотека доступа к базе....................................................................42
3.2.1. Назначение и принцип работы библиотеки.....................................42
3.2.2. Пул подключений к БД......................................................................43
3.2.3. DTO-объекты......................................................................................45
3.2.4. Атрибуты полей для DTO-объектов.................................................46
3.2.5. Репозитории доступа к таблицам......................................................46
3.2.6. Построитель SQL-запросов...............................................................49
4. РАЗРАБОТКА БАЗЫ ДАННЫХ...................................................................51
4.1. Схема Directories....................................................................................52
4.1.1. Таблица EnergyPrecisionClasses........................................................52
4.1.2. Таблица NetworkQualityPrecisionClasses..........................................54
4.1.3. Таблица VerificationMethods..............................................................55
4.2. Схема ElectricMeters..............................................................................57
4.2.1. Таблица PrecisionParametersTemplates..............................................57
4.2.2. Таблица Models...................................................................................60
4.2.3. Таблица Devices..................................................................................62
4.3. Схема WorkshopInformation..................................................................64
4.3.1. Таблица WorkPlaces............................................................................64
4.3.2. Таблица Users......................................................................................65
4.3.3. Таблица WorkShifts............................................................................66
5. РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ.............................................................68
6. ОПИСАНИЕ РАБОЧЕГО МЕСТА ОПЕРАТОРА.......................................77
7. ТЕСТИРОВАНИЕ СИСТЕМЫ......................................................................79
7.1. Цель испытаний.....................................................................................79
7.2. Технические требования.......................................................................80
7.3. Порядок проведения испытаний..........................................................80
7.4. Процесс и анализ результатов тестирования......................................81
ЗАКЛЮЧЕНИЕ.....................................................................................................83
7
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ............................................84
ПРИЛОЖЕНИЕ А.................................................................................................85
ПРИЛОЖЕНИЕ Б................................................................................................110
8
ВВЕДЕНИЕ
9
Существует множество систем управления оборудованием для различных
производств. Они отличаются масштабом решаемых задач – от отдельных
управляющий программ, встроенных в станок или агрегат, до удаленных
систем, контролирующих весь цикл производства: от обработки заявок и
формирования размеров партии, планирования и прохождения каждого этапа
технологического процесса до упаковки и учета конечной продукции.
Актуальность работы: в связи с разработкой нового вида продукции –
электросчетчиков, ООО «НПП Тепловодохран» необходима
информационная система для автоматизации процесса их производственной
настройки.
11
1. ТЕОРЕТИЧЕСКОЕ ОБОСНОВАНИЕ ТЕМЫ
ПРОЕКТА
12
получаемой информации и своевременного выявления различных
неисправностей и отклонений в измерениях все они подвергаются
регулярной поверке – в соответствии со статьей 13-ой Закона № 102 РФ «Об
обеспечении единства измерений».
Поверкой называется комплекс мероприятий, осуществляемых для
определения соответствия прибора (средства измерения) заявленным
метрологическим требованиям и нормам.
14
1.3. Периодическая поверка
17
По результатам поверки также оформляется документация, объем и
содержание которой строго регламентируется соответствующими
нормативными документами. Средство измерения при этом снабжается
поверочным клеймом, подтверждающим тот факт, что оно соответствует
законодательству и метрологическим требованиям РФ и может
эксплуатироваться в местах установки до проведения очередной
периодической поверки. Кроме того, поверительное клеймо устанавливается
таким образом, чтобы исключить доступ к внутренним датчикам и
механизмам прибора с целью вмешательства в его работу. В некоторых
случаях поверительное клеймо особого типа устанавливается на неисправные
приборы для предотвращения случаев их использования, когда они служат
доказательствами в суде, в ходе расследования различных преступлений и
т.д. Виды и области использования поверительных клейм регламентируются
ПР 50.2.007-2002 «ГСИ. Поверительные клейма».
18
С целью уменьшения брака поверки вводится контрольный допуск
(допустимая погрешность) поверки, с которым сравниваются результаты
проведенных испытаний. Для установки допустимой погрешности поверки
рекомендуется использовать нормативно-технические документы МИ 187-86
«ГСИ. Критерии достоверности и параметры методик поверки» и МИ 188-86
«ГСИ. Установление значений параметров методик поверки» и изложенные в
них способы расчета допустимой погрешности. При определении критериев
и методик поверки и уровня ее достоверности необходимо учитывать ряд
факторов, специфических для каждой группы средств измерения.
19
По результатам калибровки на приборе устанавливается соответствующее
клеймо, а в паспорт СИ заносится соответствующая запись, подтверждающая
проведение калибровки в определенных условиях.
20
2. АНАЛИЗ ТЕХНИЧЕСКОГО ЗАДАНИЯ
22
Рис. 1: Окно IDE Microsoft Visual Studio 2019 Enterprise Edition
24
Рис. 4: Схематичное представление устройства ПАК CALegration.
26
Рис. 6: Pover1C
27
2.4. Выбор модели данных
29
3. РАЗРАБОТКА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
1
Базовый функционал реализует четыре вида запросов: GET, POST, PUT и DELETE. Поддержка других
типов возможна путем наследования от базового обработчика запроса и определения функциональности для
реализуемых методов HTTP-запросов.
2
Работу с параметрами limit и offset необходимо реализовывать отдельно. В тексте они представлены лишь
в качестве примера использования «условий запроса».
30
3.1.2. Обработчик запроса (DefaultHandler и
RequestHandler)
Класс DefaultHandler
Для обработки входящих запросов необходимо создавать и
регистрировать в сервере соответствующие обработчики запросов. Базовый
класс DefaultHandler реализует функционал по генерации стандартных
кодов ответа, функционал по сериализации и десериализации данных.
31
сервере. По умолчанию веб-сервер возвращает код ответа 403 – Forbidden и
закрывает запрос, если сервер нашел обработчик запроса для
зарегистрированного URI, но не нашел подходящего метода.
Класс RequestHandler
Данный класс предоставляет верхний уровень для создания своих
обработчиков запросов. Он реализует виртуальные методы для стандартных
запросов GET, POST, PUT и DELETE.
32
параметры, то необходимо создавать перегруженный метод с необходимым
набором параметров.
По умолчанию при вызове методов, которые не были переопределены
возвращается код ответа 405 – Not allowed.
Класс UriInfo.
В базовом классе запроса DefaultHandler присутствует поле UriInfo,
которое содержит в себе информацию о URI.
33
3.1.4. Веб-сервер. Схема работы.
34
Рис. 12: Блок-схема принципиальной работы веб-сервера.
35
приходится переопределять метод и указывать ему набор входящих
параметров.
[4]
Благодаря развитому механизму рефлексии в языке C#, можно с
легкостью проверить какие методы описаны в классе и вызвать нужный.
Ниже на рисунке 13 приведен листинг метода FindRequestHandlerMethod:
37
3.1.6. Описание функции прослушивания входящих
запросов.
38
Рис. 16: Блок-схема метода ListenRequests.
39
3.1.7. Пример создания серверного приложения
40
Однако, этот пример только в целом показывает работу. Для реализации
[7]
Web-API необходимо преобразования объектов в JSON и передача их
клиенту. Для этого создадим пример обработчика запроса.
42
Рис. 22: Общая структура библиотеки
43
Рис. 23: Структура класса EMC.DataBase.Connections.Pool
3.2.3. DTO-объекты.
46
Базовый класс репозитория является обобщенным классом, где T – класс
DTO-объекта.
По умолчанию репозиторий имеет следующие методы:
Получение одной записи по идентификатору
Получение всех записей таблицы
Создание новой записи в таблице
Изменение существующей записи в таблице
Удаление записи в таблице
[4]
Благодаря реализации класса в качестве обобщенного , разработчик
информационной системы в дальнейшем будет избавлен от написания
[6]
однотипного кода . Это снижает издержки на разработку, повышает
стабильность работы приложения (в случае обнаружения ошибки достаточно
ее исправить в одном месте) и повышает скорость разработки.
Благодаря использованию атрибутов, класс-репозиторий реализует
функционал по десериализации данных БД в DTO-объект. Этот функционал
реализован в методе ParseReader.
47
Внутри функции выполняется цикл FOR, в котором происходит перебор
всех полей DTO-объекта с атрибутом DbField. Получая из атрибута
информацию о имени колонки, появляется возможность автоматически
вычислить её индекс в результате выборки и заполнить поля объекта.
Благодаря реализованному функционалу разработка становится
максимально упрощенной. Ниже представлены листинг DTO-объекта
PrecisionClass, описывающего таблицу Directories.PrecisionClasses и
48
Рис. 30: Листинг класса PrecisionClassRepository.
49
Рис. 32: Структура класса QueryBuilder.
50
4. РАЗРАБОТКА БАЗЫ ДАННЫХ
51
4.1. Схема Directories
53
4.1.2. Таблица NetworkQualityPrecisionClasses.
54
Имя: MinLimit
Описание: Минимальное допустимое отклонение, %
Тип данных: Дробный
Свойства: Значение не может быть NULL
Имя: MaxLimit
Описание: Максимальное допустимое отклонение, %
Тип данных: Дробный
Свойства: Значение не может быть NULL
Имя: IsAbsoluteDeviation
Описание: Признак абсолютного значения допусков (по
умолчанию допуски относительные в процентах)
Тип данных: Булево
Свойства: Значение не может быть NULL
55
Описание полей таблицы:
Имя: Id
Описание: Идентификатор записи в таблице
Тип данных: GUID
Свойства: Ключевое поле
Имя: Deleted
Описание: Флаг пометки записи на удаление
Тип данных: Булево
Свойства: Значение не может быть NULL
Имя: DecimalNumber
Описание: Децимальный номер методики поверки
Тип данных: Строковый
Свойства: Уникальное значение; Значение не может быть NULL
Имя: IsActual
Описание: Признак актуальности методики поверки
Тип данных: Булево
Свойства: Значение не может быть NULL
56
4.2. Схема ElectricMeters
57
Рис. 40: Схема таблиы PrecisionParametersTemplates
Описание полей таблицы:
Имя: Id
Описание: Идентификатор записи в таблице
Тип данных: GUID
Свойства: Ключевое поле
Имя: Deleted
Описание: Флаг пометки записи на удаление
Тип данных: Булево
Свойства: Значение не может быть NULL
Имя: Name
Описание: Имя шаблона классов точностей
Тип данных: Строковый
Свойства: Уникальное значение; Значение не может быть NULL
Имя: Description
Описание: Описание шаблона классов точностей
Тип данных: Строковый
Свойства:
Имя: ActiveEnergyPrecisionClassId
Описание: Класс точности активной энергии
Тип данных: GUID
Свойства: Связь 1-n к таблице EnergyPrecisionClasses; Значение не
может быть NULL
Имя: ReactiveEnergyPrecisionClassId
Описание: Класс точности реактивной энергии
Тип данных: GUID
Свойства: Связь 1-n к таблице EnergyPrecisionClasses; Значение не
может быть NULL
Имя: ActivePowerPrecisionClassId
58
Описание: Класс точности активной мощности
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
Имя: ReactivePowerPrecisionClassId
Описание: Класс точности реактивной мощности
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
Имя: FullPowerPrecisionClassId
Описание: Класс точности полной мощности
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
Имя: CurrentPrecisionClassId
Описание: Класс точности контроля тока
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
Имя: VoltagePrecisionClassId
Описание: Класс точности контроля напряжения
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
Имя: FrequencyPrecisionClassId
Описание: Класс точности контроля частоты сети
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
59
Имя: ClockPrecisionClassId
Описание: Класс точности контроля хода часов
Тип данных: GUID
Свойства: Связь 1-n к таблице NetworkQualityPrecisionClasses;
Значение не может быть NULL
60
Описание: Флаг пометки записи на удаление
Тип данных: Булево
Свойства: Значение не может быть NULL
Имя: Name
Описание: Имя модели электросчетчика
Тип данных: Строковый
Свойства: Уникальное значение; Значение не может быть NULL
Имя: Description
Описание: Описание модели электросчетчика
Тип данных: Строковый
Свойства:
Имя: DeviceType
Описание: Тип электросчетчика
Тип данных: Целое число
Свойства: Значение не может быть NULL
Имя: PrecisionParametersTemplateId
Описание: Ссылка на шаблон с классами точности
Тип данных: GUID
Свойства: Связь 1-n к таблице PrecisionParametersTemplates;
Значение не может быть NULL
Имя: NominalVoltage
Описание: Номинальное напряжение, В
Тип данных: Дробное число
Свойства: Значение не может быть NULL
Имя: NominalCurrent
Описание: Номинальный ток, А
Тип данных: Дробное число
Свойства: Значение не может быть NULL
Имя: MaximumVoltage
61
Описание: Максимальное напряжение, В
Тип данных: Дробное число
Свойства: Значение не может быть NULL
Имя: MaximumCurrent
Описание: Максимальный ток, А
Тип данных: Дробное число
Свойства: Значение не может быть NULL
Имя: Ratio
Описание: Передаточное отношение
Тип данных: Целое число
Свойства: Значение не может быть NULL
Имя: Manufacturer
Описание: Производитель электросчетчика
Тип данных: Строковый
Свойства: Значение не может быть NULL
Имя: StateRegistryNumber
Описание: Номер регистрации модели в госреестре
Тип данных: Строковый
Свойства: Значение не может быть NULL
Имя: VerificationMethodId
Описание: Ссылка на методику поверки
Тип данных: GUID
Свойства: Связь 1-n к таблице VerificationMethods; Значение не
может быть NULL
63
4.3. Схема WorkshopInformation
66
Рис. 46: Схема таблицы WorkShifts
67
5. РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ
69
Рис. 49: Выбор сценария поверки
После того, как оператор укажет тип сценария (настройка и/или поверка),
укажет модель прибора и выберет точки сценария, следом за этим начнется
процесс настройки или поверки и отобразится окно с индикацией процесса
выполнения сценария.
70
Рис. 51: Окно отображения процесса выполнения сценария
71
Рис. 53: Диалоговое окно настроек приложения
В данном диалоговом окне можно указать порт для связи с устройствами,
сетевые адреса для источников фиктивной мощности, эталонного счетчика и
блока силовых реле.
В случае, если источник мощности выбран как трехфазный, то блок
силовых реле не используется.
73
Кнопка «Сценарии» открывает форму для редактирования сценариев
настройки и поверки. На форме отображается список сценариев и связанных
с ними точек (параметры тока, напряжения, частоты сети и т.д.).
74
В дереве сценариев отображается список сценариев хранящихся в базе
данных информационной системы.
76
6. ОПИСАНИЕ РАБОЧЕГО МЕСТА ОПЕРАТОРА
78
7. ТЕСТИРОВАНИЕ СИСТЕМЫ
80
проверка правильного соединения между серверной и клиентской
частью;
проверка правильного отображения данных клиентской части;
проверка корректной функциональности таблиц базы данных;
проверка работы основной и вспомогательной функциональной
части системы;
проверка корректности выгрузки данных из системы.
81
Программное обеспечение клиентской части имела стабильное
соединение с измерительными приборами и устройствами, которые
поверялись на установке. Удалось успешно откалибровать (настроить) и
поверить группу из двадцати электросчетчиков.
Данные испытания показывают корректность работы информационной
системы производственной настройки и поверки электросчетчиков. Во время
тестирования сбоев обнаружено не было.
82
ЗАКЛЮЧЕНИЕ
83
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
84
ПРИЛОЖЕНИЕ А
Модуль Pulsar.HttpServer
// Выполнил студент гр. 6040 Сухоруков Д.В.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Pulsar.HttpServer.Exceptions;
using Pulsar.HttpServer.Handlers;
using Pulsar.HttpServer.Uri;
namespace Pulsar.HttpServer
{
/// <summary>
/// Класс HTTP-сервера
/// </summary>
public sealed class HttpServer
{
#region private & constructor
/// <summary>
/// Прослушиватель протокола HTTP
/// </summary>
private HttpListener httpListener;
/// <summary>
/// Сигнал отмены
/// </summary>
private CancellationTokenSource cancellationTokenSource;
/// <summary>
/// Словарь зарегистрированных обработчиков URI
/// </summary>
private readonly Dictionary<UriInfo, Type> registeredHandlers;
/// <summary>
/// Возвращает экземпляр класса <see cref="HttpServer"/>
/// </summary>
/// <exception cref="OperatingSystemNotSupportedException">Ошибка
возникает в том случае, если версия операционной системы не
поддерживается.</exception>
public HttpServer()
{
85
if (!HttpListener.IsSupported)
throw new OperatingSystemNotSupportedException();
Host = DEFAULT_HOST;
Port = DEFAULT_PORT;
UseHttps = DEFAULT_USE_HTTPS;
ConcurrentRequestsCount = DEFAULT_CONCURRENT_REQUESTS_COUNT;
/// <summary>
/// Создание URL-строки прослушивания
/// </summary>
/// <returns>URL-строка для прослушивания</returns>
private string BuildUrlListeningString()
{
var protocol = UseHttps ? "https" : "http";
return $"{protocol}://{Host}:{Port}/";
}
/// <summary>
/// Метод прослушивания входящих запросов
/// </summary>
private async void ListenRequests()
{
var cancellationToken = cancellationTokenSource.Token;
var taskQueue = new HashSet<Task>();
if (cancellationToken.IsCancellationRequested)
break;
taskQueue.Add(ProcessHttpRequestAsync(httpRequestTask.Result));
taskQueue.Add(httpListener.GetContextAsync());
}
}
}
/// <summary>
/// Поиск зарегистрированного обработчика запроса по информации URI
/// </summary>
/// <param name="uriInfo">Информация URI</param>
/// <param name="uriTemplate">Возвращаемый шаблон URI</param>
86
/// <returns>Класс обработчика запроса или null, если обработчик не
найден</returns>
private Type FindRegisteredHandlerType(UriInfo uriInfo, out UriInfo
uriTemplate)
{
uriTemplate = null;
return null;
}
/// <summary>
/// Поиск метода обработчика запроса
/// </summary>
/// <param name="requestHandler">Обработчик запроса</param>
/// <param name="httpMethod">Метод HTTP</param>
/// <param name="uriInfo">Информация о URI</param>
/// <returns>Метод или null, если соответствующий метод в обработчике не
обнаружен</returns>
private MethodInfo FindRequestHandlerMethod(RequestHandler
requestHandler, string httpMethod, UriInfo uriInfo)
{
var uriParameters = uriInfo.UriElements.Where(p => p.UriType !=
UriType.Uri).ToArray();
if (uriParameters.Length != methodParameters.Length)
continue;
if (!
parameter.Name.ToUpper().Equals(methodParameter.Name.ToUpper()))
{
isDesiredMethod = false;
break;
}
}
if (isDesiredMethod)
return method;
}
87
return null;
}
/// <summary>
/// Ответ с кодом 404 "Метод не найден"
/// </summary>
/// <param name="context">Контекст запроса</param>
/// <returns>Асинхронная операция</returns>
private Task HandlerNotFoundResponseAsync(HttpListenerContext context)
{
return Task.Run(new DefaultHandler(context).NotFound);
}
/// <summary>
/// Ответ с кодом 405 "Метод не допускается"
/// </summary>
/// <param name="context">Контекст запроса</param>
/// <returns>Асинхронная операция</returns>
private Task HandlerNotAllowedResponseAsync(HttpListenerContext context)
{
return Task.Run(new DefaultHandler(context).NotAllowed);
}
/// <summary>
/// Выполнить метод обработчика запроса
/// </summary>
/// <param name="requestHandler">Обработчик запроса</param>
/// <param name="method">Метод к выполнению</param>
/// <param name="parameters">Входящие параметры метода</param>
/// <returns>Асинхронная операция</returns>
private Task HandlerProcessMethodAsync(RequestHandler requestHandler,
MethodInfo method, object[] parameters)
{
return Task.Run(() =>
{
try
{
method.Invoke(requestHandler, parameters);
}
catch (Exception e)
{
requestHandler.InternalError(e.InnerException == null ?
e.Message : e.InnerException.Message);
}
});
}
/// <summary>
/// Метод обработки входящего HTTP-запроса
/// </summary>
/// <param name="context">Контекст запроса</param>
/// <returns>Задача, обслуживающая обработку запроса</returns>
private Task ProcessHttpRequestAsync(HttpListenerContext context)
{
var uriInfo = new UriInfo(context.Request.Url.PathAndQuery);
if (handlerType == null)
88
return HandlerNotFoundResponseAsync(context);
#endregion
#region public
/// <summary>
/// Флаг необходимости использования сертификата
/// </summary>
public bool UseHttps { get; set; }
/// <summary>
/// Хост (домен) сервера
/// </summary>
/// <remarks>Чтобы получить все запросы отправленные на порт сервера, то
значение Host должно быть указано как "*". Однако не следует использовать привязки
верхнего уровня
/// (http://*:8080/ и http://+:8080), так как это может создать
уязвимость и поставить ваше приложение под угрозу.</remarks>
public string Host { get; set; }
/// <summary>
/// Порт сервера
/// </summary>
public int Port { get; set; }
/// <summary>
/// Количество одновременно обрабатываемых запросов. Если значение равно
0, то количество запросов равно количеству процессоров в системе
/// </summary>
public int ConcurrentRequestsCount { get; set; }
/// <summary>
/// Возвращает значение был ли запущен HTTP-сервер
/// </summary>
public bool IsRunning => httpListener != null &&
httpListener.IsListening;
/// <summary>
/// URL-строка прослушиваемая сервером
/// </summary>
public string ListeningUrl => BuildUrlListeningString();
/// <summary>
/// Запуск сервера
/// </summary>
public void Start()
{
cancellationTokenSource = new CancellationTokenSource();
89
httpListener.Prefixes.Clear();
httpListener.Prefixes.Add(ListeningUrl);
httpListener.Start();
ListenRequests();
}
/// <summary>
/// Остановка сервера
/// </summary>
public void Stop()
{
if (!IsRunning)
return;
cancellationTokenSource.Cancel();
httpListener.Close();
}
/// <summary>
/// Регистрация обработчика запроса
/// </summary>
/// <param name="uri">URI запроса</param>
/// <param name="handlerType">Обработчик запроса</param>
public void RegisterHandler(string uri, Type handlerType)
{
registeredHandlers.Add(new UriInfo(uri), handlerType);
}
#endregion
}
}
90
Модуль Pulsar.HttpServer.Handlers.DefaultHandler
// Выполнил студент гр. 6040 Сухоруков Д.В.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Principal;
using System.Text;
using System.Threading;
using Newtonsoft.Json;
using Pulsar.HttpServer.Uri;
namespace Pulsar.HttpServer.Handlers
{
/// <summary>
/// Базовый обработчик запросов
/// </summary>
public class DefaultHandler
{
/// <summary>
/// Информация о URI
/// </summary>
protected readonly UriInfo UriInfo;
/// <summary>
/// Возвращает экземпляр класса <see cref="DefaultHandler"/>
/// </summary>
/// <param name="context">Контекст HTTP-запроса</param>
public DefaultHandler(HttpListenerContext context)
{
UriInfo = new UriInfo(context.Request.Url.PathAndQuery);
Request = context.Request;
Response = context.Response;
User = context.User;
}
/// <summary>
/// Возвращает объект, используемый для получения идентификации, сведений
проверки подлинности и ролей безопасности для клиента
/// </summary>
protected IPrincipal User { get; }
/// <summary>
/// Входящий HTTP-запрос
/// </summary>
protected HttpListenerRequest Request { get; }
/// <summary>
/// Ответ на HTTP-запрос
/// </summary>
protected HttpListenerResponse Response { get; }
/// <summary>
/// Обращение к параметру запроса по имени
/// </summary>
/// <param name="name">Имя параметра</param>
91
/// <returns>Параметр запроса или null, если параметр не найден</returns>
protected UriParameter GetRequestParameter(string name)
{
return UriInfo.Parameters.FirstOrDefault(parameter =>
parameter.Name.ToLower().Equals(name.ToLower()));
}
/// <summary>
/// Завершить запрос
/// </summary>
public void Close()
{
Response.Close();
}
/// <summary>
/// Завершить запрос с кодом выполнения
/// </summary>
/// <param name="statusCode">Код выполнения</param>
public void Finish(int statusCode = 200)
{
Response.StatusCode = statusCode;
Close();
}
/// <summary>
/// Отправить в ответ массив байт
/// </summary>
/// <param name="data">Отправляемый массив байт</param>
public void Write(byte[] data)
{
Response.ContentLength64 = data.Length;
var output = Response.OutputStream;
output.Write(data, 0, data.Length);
}
/// <summary>
/// Отправить в ответ текстовые данные
/// </summary>
/// <param name="data">Текстовые данные</param>
public void Write(string data)
{
Response.ContentEncoding = Encoding.UTF8;
Response.ContentType = "text/html; charset=UTF-8";
Write(System.Text.Encoding.UTF8.GetBytes(data));
}
/// <summary>
/// Отправить в ответ объект
/// </summary>
/// <param name="data">Отправляемый объект</param>
public void Write(object data)
{
var json = JsonConvert.SerializeObject(data);
Response.ContentType = "application/json";
Write(json);
}
/// <summary>
92
/// Отправить в ответ файл
/// </summary>
/// <param name="path">Путь до файла</param>
/// <param name="fileName">Отображаемое имя файла при загрузке</param>
/// <param name="downloadSpeedLimit">Ограничение скорости загрузки в
байтах. Минимальная скорость 65 кб/с</param>
/// <exception cref="HttpListenerException"></exception>
public void WriteFile(string path, string fileName, int
downloadSpeedLimit = 0)
{
var mimeTypeMappings = new Dictionary<string,
string>(StringComparer.InvariantCultureIgnoreCase)
{
#region extension to MIME type list
{".asf", "video/x-ms-asf"},
{".asx", "video/x-ms-asf"},
{".avi", "video/x-msvideo"},
{".bin", "application/octet-stream"},
{".cco", "application/x-cocoa"},
{".crt", "application/x-x509-ca-cert"},
{".css", "text/css"},
{".deb", "application/octet-stream"},
{".der", "application/x-x509-ca-cert"},
{".dll", "application/octet-stream"},
{".dmg", "application/octet-stream"},
{".ear", "application/java-archive"},
{".eot", "application/octet-stream"},
{".exe", "application/octet-stream"},
{".flv", "video/x-flv"},
{".gif", "image/gif"},
{".hqx", "application/mac-binhex40"},
{".htc", "text/x-component"},
{".htm", "text/html"},
{".html", "text/html"},
{".ico", "image/x-icon"},
{".img", "application/octet-stream"},
{".iso", "application/octet-stream"},
{".jar", "application/java-archive"},
{".jardiff", "application/x-java-archive-diff"},
{".jng", "image/x-jng"},
{".jnlp", "application/x-java-jnlp-file"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".js", "application/x-javascript"},
{".mml", "text/mathml"},
{".mng", "video/x-mng"},
{".mov", "video/quicktime"},
{".mp3", "audio/mpeg"},
{".mpeg", "video/mpeg"},
{".mpg", "video/mpeg"},
{".msi", "application/octet-stream"},
{".msm", "application/octet-stream"},
{".msp", "application/octet-stream"},
{".pdb", "application/x-pilot"},
{".pdf", "application/pdf"},
{".pem", "application/x-x509-ca-cert"},
{".pl", "application/x-perl"},
{".pm", "application/x-perl"},
{".png", "image/png"},
{".prc", "application/x-pilot"},
{".ra", "audio/x-realaudio"},
93
{".rar", "application/x-rar-compressed"},
{".rpm", "application/x-redhat-package-manager"},
{".rss", "text/xml"},
{".run", "application/x-makeself"},
{".sea", "application/x-sea"},
{".shtml", "text/html"},
{".sit", "application/x-stuffit"},
{".swf", "application/x-shockwave-flash"},
{".tcl", "application/x-tcl"},
{".tk", "application/x-tcl"},
{".txt", "text/plain"},
{".war", "application/java-archive"},
{".wbmp", "image/vnd.wap.wbmp"},
{".wmv", "video/x-ms-wmv"},
{".xml", "text/xml"},
{".xpi", "application/x-xpinstall"},
{".zip", "application/zip"},
#endregion
};
var downloadDelay = 0;
Response.ContentType =
mimeTypeMappings.TryGetValue(Path.GetExtension(path), out var mime)
? mime
: "application/octet-stream";
Response.ContentType =
System.Net.Mime.MediaTypeNames.Application.Octet;
//Response.AddHeader("Content-disposition", $"attachment;
filename={fileName}");
// Response.AddHeader("Content-Type", $"attachment;
filename={fileName}");
if (downloadDelay > 0)
94
Thread.Sleep(downloadDelay);
}
}
finally
{
bw.Close();
}
}
}
}
/// <summary>
/// Возвращает ошибку 405 "Метод не допускается"
/// </summary>
public void NotAllowed()
{
Response.StatusCode = 405;
Response.StatusDescription = "Method not allowed";
Close();
}
/// <summary>
/// Метод не найден
/// </summary>
public void NotFound()
{
Response.StatusCode = 404;
Response.StatusDescription = "Not found";
Close();
}
/// <summary>
/// Внутренняя ошибка сервера
/// </summary>
public void InternalError(string message = "")
{
Response.StatusCode = 500;
Response.StatusDescription = "Internal server error";
Write(message);
Close();
}
/// <summary>
/// Для доступа к запрашиваемому ресурсу требуется аутентификация
/// </summary>
public void Unauthorized()
{
Response.StatusCode = 401;
Response.StatusDescription = "Unauthorized";
Close();
}
/// <summary>
/// Отказано в доступе к запрашиваемому ресурсу
/// </summary>
public void Forbidden()
95
{
Response.StatusCode = 403;
Response.StatusDescription = "Forbidden";
Close();
}
/// <summary>
/// Запрос обработан успешно
/// </summary>
public void Success()
{
Response.StatusCode = 200;
Response.StatusDescription = "Success";
Close();
}
/// <summary>
/// Десериализовать входящие данные
/// </summary>
/// <typeparam name="T">Тип десериализации</typeparam>
/// <returns>Десериализованный объект</returns>
public T DeserializeJsonBody<T>()
{
var reader = new StreamReader(Request.InputStream,
Request.ContentEncoding);
if (Request.ContentType == null || !
Request.ContentType.ToUpper().Equals("application/json".ToUpper()))
return default(T);
return JsonConvert.DeserializeObject<T>(reader.ReadToEnd());
}
}
}
96
Модуль Pulsar.HttpServer.Handlers.RequestHandler
// Выполнил студент гр. 6040 Сухоруков Д.В.
using System;
using System.Net;
using System.Threading.Tasks;
namespace Pulsar.HttpServer.Handlers
{
/// <summary>
/// Обработчик запроса
/// </summary>
public class RequestHandler : DefaultHandler
{
public RequestHandler(HttpListenerContext context) : base(context)
{
}
/// <summary>
/// Метод GET
/// </summary>
public virtual void Get()
{
NotAllowed();
}
/// <summary>
/// Метод POST
/// </summary>
public virtual void Post()
{
NotAllowed();
}
/// <summary>
/// Метод PUT
/// </summary>
public virtual void Put()
{
NotAllowed();
}
/// <summary>
/// Метод DELETE
/// </summary>
public virtual void Delete()
{
NotAllowed();
}
/// <summary>
/// Обработать запрос
/// </summary>
/// <returns></returns>
public Task HandleRequest()
{
return Task.Run(() =>
{
Write("<b>Hello world!</b>");
Finish();
97
});
98
Модуль EMC.DataBase.Repositories.Repository
// Выполнил студент гр. 6040 Сухоруков Д.В.
using System;
using System.Collections.Generic;
using System.Reflection;
using Npgsql;
using EMC.DataBase.Attributes;
using EMC.DataBase.DTO;
using EMC.DataBase.Exceptions;
using EMC.DataBase.Sql;
using EMC.DataBase.Sql.Queries.Conditions;
namespace EMC.DataBase.Repositories
{
/// <summary>
/// Базовый класс репозитория сущностей БД.
/// </summary>
/// <typeparam name="T">Сущность БД</typeparam>
public class Repository<T> where T : Dto
{
/// <summary>
/// Соединение с базой данных.
/// </summary>
protected readonly NpgsqlConnection connection;
/// <summary>
/// Конструктор по умолчанию.
/// </summary>
/// <param name="connection">Соединение с базой данных.</param>
public Repository(NpgsqlConnection connection)
{
this.connection = connection;
}
/// <summary>
/// Десериализация входящих данных в dto.
/// </summary>
/// <param name="reader"></param>
/// <returns>Экземпляр dto.</returns>
protected virtual T ParseReader(NpgsqlDataReader reader)
{
var dtoType = typeof(T);
if (dbField == null)
continue;
var value =
reader.GetValue(reader.GetOrdinal(dbField.FieldName));
propertyInfo.SetValue(result, value);
}
return result;
99
}
/// <summary>
/// Выполнение SQL-запроса.
/// </summary>
/// <param name="sql">SQL-запрос.</param>
protected void ExecuteNonQuery(string sql)
{
var command = new NpgsqlCommand(sql, connection);
using (command)
{
command.ExecuteNonQuery();
}
}
/// <summary>
/// Выполнение SQL-запроса с параметрами.
/// </summary>
/// <param name="sql">SQL-запрос.</param>
/// <param name="parameters">Параметры запроса.</param>
protected void ExecuteNonQuery(string sql, Dictionary<string, object>
parameters)
{
using (var cmd = new NpgsqlCommand(sql, connection))
{
foreach (var parameter in parameters)
cmd.Parameters.AddWithValue(parameter.Key, parameter.Value);
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// Выполнение запроса.
/// </summary>
/// <param name="sql">Текст запроса.</param>
/// <param name="func">Функция десериализации.</param>
/// <param name="parameters">Параметры запроса.</param>
/// <returns>Коллекция dto-объектов.</returns>
protected List<T> ExecuteQuery(string sql, Func<NpgsqlDataReader, T>
func, Dictionary<string, object> parameters = null)
{
var result = new List<T>();
if (item != null)
result.Add(item);
}
100
}
reader.Close();
}
return result;
}
/// <summary>
/// Выполнение запроса.
/// </summary>
/// <param name="sql">Текст запроса.</param>
/// <param name="parameters">Параметры запроса.</param>
/// <returns>Коллекция dto-объектов.</returns>
protected List<T> ExecuteQuery(string sql, Dictionary<string, object>
parameters = null)
{
return ExecuteQuery(sql, ParseReader, parameters);
}
/// <summary>
/// Получение всех записей таблицы.
/// </summary>
/// <param name="deleted">Добавлять в выборку записи с пометкой на
удаление.</param>
/// <returns>Коллекция записей.</returns>
public List<T> Get(bool deleted = false)
{
var sql = new QueryBuilder(typeof(T))
.Select()
.Where(new[] {("Deleted", ConditionMode.And)});
/// <summary>
/// Получение записи таблицы по идентификатору.
/// </summary>
/// <param name="id">Идентификатор записи.</param>
/// <param name="deleted">Добавлять в выборку записи с пометкой на
удаление.</param>
/// <returns>Запись базы данных.</returns>
/// <exception cref="IncorrectMethodUsingException"></exception>
public T Get(Guid id, bool deleted = false)
{
if (id == Guid.Empty)
throw new IncorrectMethodUsingException("Can not get record with
empty entity id.");
101
{
{$"@{nameof(id).ToLower()}", id},
{$"@{nameof(deleted).ToLower()}", deleted}
};
/// <summary>
/// Пометить запись таблицы на удаление.
/// </summary>
/// <param name="id">Идентификатор записи.</param>
/// <exception cref="IncorrectMethodUsingException"></exception>
public void Delete(Guid id)
{
if (id == Guid.Empty)
throw new IncorrectMethodUsingException("Can not to mark record
as deleted empty entity id.");
transaction.Commit();
}
finally
{
transaction.Rollback();
}
}
/// <summary>
/// Добавить новую запись в таблицу.
/// </summary>
/// <param name="entity">Добавляемая сущность.</param>
/// <returns>Созданная запись БД.</returns>
public T Save(T entity)
{
if (entity.Deleted)
throw new IncorrectMethodUsingException("Can not to insert record
marked as deleted.");
102
var dbField =
(DbFieldAttribute)propertyInfo.GetCustomAttribute(typeof(DbFieldAttribute));
if (dbField == null)
continue;
return result;
}
finally
{
transaction.Rollback();
}
}
/// <summary>
/// Обновляет запись в таблице.
/// </summary>
/// <remarks>Данным методом невозможно пометить запись на удаление. Для
этого необходимо использовать метод <see cref="Delete"/>.</remarks>
/// <param name="entity">Обновляемая сущность.</param>
/// <returns>Обновленная запись БД.</returns>
/// <exception cref="IncorrectMethodUsingException"></exception>
public T Update(T entity)
{
if (entity.Deleted)
throw new IncorrectMethodUsingException("This method cannot mark
the record for deletion or update record marked as deleted.");
if (entity.Id == Guid.Empty)
throw new IncorrectMethodUsingException("Can not to update record
with empty entity id.");
103
fields.Add(dbField.FieldName);
parameters.Add(key, propertyInfo.GetValue(entity));
}
try
{
ExecuteNonQuery(sql.AsString(), parameters);
transaction.Commit();
return (T)entity.Copy();
}
finally
{
transaction.Rollback();
}
}
}
}
104
Модуль EMC.DataBase.SQL.QueryBuilder
// Выполнил студент гр. 6040 Сухоруков Д.В.
using System;
using System.Collections.Generic;
using System.Reflection;
using EMC.DataBase.Attributes;
using EMC.DataBase.Exceptions;
using EMC.DataBase.Sql.Queries;
namespace EMC.DataBase.Sql
{
/// <summary>
/// Построитель SQL-запросов.
/// </summary>
public class QueryBuilder
{
/// <summary>
/// Тип dto-объектов для которых строятся запросы.
/// </summary>
private readonly Type dtoType;
/// <summary>
/// Возвращает экземпляр класса.
/// </summary>
/// <param name="dtoType">Тип dto-объектов.</param>
public QueryBuilder(Type dtoType)
{
this.dtoType = dtoType;
}
/// <summary>
/// Извлекает коллекцию доступных полей таблицы БД.
/// </summary>
/// <returns>Коллекция полей БД.</returns>
private List<string> ExtractFields()
{
var result = new List<string>();
return result;
}
/// <summary>
/// Извлекает имя схемы БД.
/// </summary>
/// <returns>Имя съемы БД.</returns>
private string ExtractSchemeName()
{
var dbScheme =
(DbSchemeAttribute)dtoType.GetCustomAttribute(typeof(DbSchemeAttribute));
105
}
/// <summary>
/// Извлекает имя таблицы БД.
/// </summary>
/// <returns>Имя таблицы БД.</returns>
private string ExtractTableName()
{
var dbTable =
(DbTableAttribute)dtoType.GetCustomAttribute(typeof(DbTableAttribute));
if (dbTable == null)
throw new AttributeNotFoundException($"Attribute
{nameof(DbTableAttribute)} not found.");
return dbTable.TableName;
}
/// <summary>
/// Создает запрос SELECT.
/// </summary>
/// <returns>SQL-запрос.</returns>
public IQuery Select()
{
var fields = ExtractFields();
var tableName = ExtractTableName();
var schemeName = ExtractSchemeName();
/// <summary>
/// Создает запрос DELETE.
/// </summary>
/// <returns>SQL-запрос.</returns>
public IQuery Delete()
{
var tableName = ExtractTableName();
var schemeName = ExtractSchemeName();
/// <summary>
/// Создает запрос UPDATE.
/// </summary>
/// <param name="fields">Список полей для обновления.</param>
/// <returns>SQL-запрос.</returns>
public IQuery Update(List<string> fields)
{
var tableName = ExtractTableName();
var schemeName = ExtractSchemeName();
/// <summary>
/// Создает запрос UPDATE.
/// </summary>
/// <returns>SQL-запрос.</returns>
public IQuery Insert()
{
106
var fields = ExtractFields();
var tableName = ExtractTableName();
var schemeName = ExtractSchemeName();
107
Модуль EMC.DataBase.SQL.Queries.Query
// Выполнил студент гр. 6040 Сухоруков Д.В.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EMC.DataBase.Sql.Queries.Conditions;
namespace EMC.DataBase.Sql.Queries
{
/// <summary>
/// Абстрактный класс SQL-запроса.
/// </summary>
internal abstract class Query : IQuery
{
/// <summary>
/// Базовый конструктор класса.
/// </summary>
/// <param name="fields">Поля таблицы БД.</param>
/// <param name="tableName">Имя таблицы БД.</param>
/// <param name="schemeName">Имя схемы БД.</param>
protected Query(List<string> fields, string tableName, string schemeName)
{
Fields = fields;
TableName = tableName;
SchemeName = schemeName;
/// <summary>
/// Поля таблицы БД.
/// </summary>
protected List<string> Fields { get; }
/// <summary>
/// Имя таблицы БД.
/// </summary>
protected string TableName { get; }
/// <summary>
/// Имя схемы БД.
/// </summary>
protected string SchemeName { get; }
/// <summary>
/// Условия запроса.
/// </summary>
protected List<Condition> Conditions { get; }
/// <summary>
/// Возвращает перечисление полей запроса в виде строки.
/// </summary>
/// <returns>Поля запроса в виде строки.</returns>
protected string BuildFieldsString()
{
var builder = new StringBuilder();
foreach (var field in Fields)
builder.Append($"\"{field}\",");
108
return builder.ToString().TrimEnd(',');
}
/// <summary>
/// Возвращает полное имя таблицы в виде строки.
/// </summary>
/// <returns>Полное имя таблицы в виде строки.</returns>
protected string BuildFullTableName()
{
return string.IsNullOrEmpty(SchemeName)
? $"\"{TableName}\""
: $"\"{SchemeName}\".\"{TableName}\"";
}
/// <summary>
/// Возвращает перечисление условий в виде строки.
/// </summary>
/// <returns>Перечисление условий в виде строки.</returns>
protected string BuildConditions()
{
if (Conditions.Count == 0)
return string.Empty;
conditionString.Append("where ");
foreach (var condition in Conditions)
{
if (condition != Conditions.First())
conditionString.Append($"
{condition.ConditionMode.AsString()} ");
conditionString.Append($" \"{condition.FieldName}\" =
@{condition.FieldName.ToLower()} ");
}
return conditionString.ToString();
}
return this;
}
}
}
109
ПРИЛОЖЕНИЕ Б
SET search_path TO
pg_catalog,public,"Scenarios","ElectricMeters","Directories","Processes","WorkshopInf
ormation";
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "ElectricMeters"."Devices" IS 'Экземпляры устройств';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Devices"."Deleted" IS 'Флаг пометки на
удаление';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Devices"."SerialNumber" IS 'Серийный номер';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Devices"."Password" IS 'Пароль устройства';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Devices"."ModelId" IS 'Модель устройства';
-- ddl-end --
ALTER TABLE "ElectricMeters"."Devices" OWNER TO postgres;
-- ddl-end --
111
);
-- ddl-end --
COMMENT ON TABLE "ElectricMeters"."Models" IS 'Модели электросчётчиков';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."Deleted" IS 'Флаг пометки на
удаление';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."Name" IS 'Название модели';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."Description" IS 'Подробное описание
модели';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."DeviceType" IS 'Тип устройства (0 -
однофазный, 1 - трёхфазный, 2 - постоянного тока, 4 - счётчик ампер-часов)';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."PrecisionParametersTemplateId" IS
'Ссылка на шаблон с классами точности';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."NominalVoltage" IS 'Номинальное
напряжение, В';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."NominalCurrent" IS 'Номинальный ток,
А';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."MaximumVoltage" IS 'Максимальное
напряжение, В';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."MaximumCurrent" IS 'Максимальный
ток, А';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."Ratio" IS 'Передаточное число,
имп/кВт*ч';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."Manufacturer" IS 'Изготовитель';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."StateRegistryNumber" IS 'Номер
регистрации модели в госреестре';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."Models"."VerificationMethodId" IS 'Ссылка на
методику поверки';
-- ddl-end --
ALTER TABLE "ElectricMeters"."Models" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "Directories"."EnergyPrecisionClasses" IS 'Классы точности для
энергии';
112
-- ddl-end --
COMMENT ON COLUMN "Directories"."EnergyPrecisionClasses"."Deleted" IS 'Флаг
пометки на удаление';
-- ddl-end --
COMMENT ON COLUMN "Directories"."EnergyPrecisionClasses"."Name" IS 'Название
класса точности';
-- ddl-end --
COMMENT ON COLUMN "Directories"."EnergyPrecisionClasses"."Description" IS
'Подробное описание';
-- ddl-end --
COMMENT ON COLUMN "Directories"."EnergyPrecisionClasses"."MinLimit" IS
'Минимальное допустимое отклонение, %';
-- ddl-end --
COMMENT ON COLUMN "Directories"."EnergyPrecisionClasses"."MaxLimit" IS
'Максимальное допустимое отклонение, %';
-- ddl-end --
COMMENT ON COLUMN "Directories"."EnergyPrecisionClasses"."IsAbsoluteDeviation" IS
'Флаг абсолютного значения допусков';
-- ddl-end --
ALTER TABLE "Directories"."EnergyPrecisionClasses" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "ElectricMeters"."PrecisionParametersTemplates" IS 'Шаблоны с
классами точности для конкретных моделей приборов';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."PrecisionParametersTemplates"."Deleted" IS
'Флаг пометки на удаление';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."PrecisionParametersTemplates"."Name" IS 'Имя
шаблона классов точностей';
-- ddl-end --
COMMENT ON COLUMN "ElectricMeters"."PrecisionParametersTemplates"."Description"
IS 'Подробное описание';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."ActiveEnergyPrecisionClassId" IS
'Класс точности активной энергии';
-- ddl-end --
113
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."ReactiveEnergyPrecisionClassId" IS
'Класс точности для реактивной энергии';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."ActivePowerPrecisionClassId" IS
'Класс точности активной мощности';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."ReactivePowerPrecisionClassId" IS
'Класс точности реактивной мощности';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."FullPowerPrecisionClassId" IS 'Класс
точности для полной мощности';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."CurrentPrecisionClassId" IS 'Класс
точности для контроля тока';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."FrequencyPrecisionClassId" IS 'Класс
точности для частоты сети';
-- ddl-end --
COMMENT ON COLUMN
"ElectricMeters"."PrecisionParametersTemplates"."ClockPrecisionClassId" IS 'Класс
точности для хода часов';
-- ddl-end --
ALTER TABLE "ElectricMeters"."PrecisionParametersTemplates" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "Directories"."NetworkQualityPrecisionClasses" IS 'Справочник
классов точности для контроля качества сети';
-- ddl-end --
COMMENT ON COLUMN "Directories"."NetworkQualityPrecisionClasses"."Deleted" IS
'Флаг пометки на удаление';
-- ddl-end --
COMMENT ON COLUMN "Directories"."NetworkQualityPrecisionClasses"."Name" IS
'Название';
-- ddl-end --
COMMENT ON COLUMN "Directories"."NetworkQualityPrecisionClasses"."Description" IS
'Подробное описание';
-- ddl-end --
COMMENT ON COLUMN "Directories"."NetworkQualityPrecisionClasses"."MinLimit" IS
'Минимальное допустимое значение';
-- ddl-end --
114
COMMENT ON COLUMN "Directories"."NetworkQualityPrecisionClasses"."MaxLimit" IS
'Максимальное допустимое значение';
-- ddl-end --
COMMENT ON COLUMN
"Directories"."NetworkQualityPrecisionClasses"."IsAbsoluteDeviation" IS 'Флаг
абсолютного значения допусков';
-- ddl-end --
ALTER TABLE "Directories"."NetworkQualityPrecisionClasses" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "Directories"."VerificationMethods" IS 'Методики поверки';
-- ddl-end --
COMMENT ON COLUMN "Directories"."VerificationMethods"."Deleted" IS 'Флаг пометки
на удаление';
-- ddl-end --
COMMENT ON COLUMN "Directories"."VerificationMethods"."DecimalNumber" IS
'Децимальный номер методики поверки';
-- ddl-end --
COMMENT ON COLUMN "Directories"."VerificationMethods"."IsActual" IS 'Флаг
актуальности методики поверки. Если значение false, то нельзя использовать
настройку/поверку с данной методикой';
-- ddl-end --
ALTER TABLE "Directories"."VerificationMethods" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "Processes"."Processes" IS 'Таблица проведенных процессов
настройки и поверки приборов';
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."BatchNumber" IS 'Номер партии
устанавливаемой на установку в рамках данного процесса';
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."ModelId" IS 'Ссылка на модель
прибора';
115
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."StateRegistryNumber" IS 'Номер
регистрации модели прибора в госреестре на момент проведения процесса настройки или
поверки';
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."VerificationMethodId" IS 'Номер
методики поверки прибора на момент проведения процесса настройки или поверки';
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."DateStart" IS 'Дата начала процесса';
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."DateEnd" IS 'Дата окончания процесса';
-- ddl-end --
COMMENT ON COLUMN "Processes"."Processes"."WorkShiftId" IS 'Ссылка на смену
оператора';
-- ddl-end --
ALTER TABLE "Processes"."Processes" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "WorkshopInformation"."Users" IS 'Операторы';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."Users"."Deleted" IS 'Флаг пометки на
удаление';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."Users"."FirstName" IS 'Имя';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."Users"."LastName" IS 'Фамилия';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."Users"."Blocked" IS 'Флаг блокировки
учетной записи оператора';
-- ddl-end --
ALTER TABLE "WorkshopInformation"."Users" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "WorkshopInformation"."WorkShifts" IS 'Рабочие смены';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkShifts"."WorkPlaceId" IS 'Ссылка на
рабочее место';
116
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkShifts"."UserId" IS 'Ссылка на
оператора';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkShifts"."DateStart" IS 'Дата начала
смены';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkShifts"."DateEnd" IS 'Дата окончания
смены';
-- ddl-end --
ALTER TABLE "WorkshopInformation"."WorkShifts" OWNER TO postgres;
-- ddl-end --
);
-- ddl-end --
COMMENT ON TABLE "WorkshopInformation"."WorkPlaces" IS 'Рабочее место MTE';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkPlaces"."Deleted" IS 'Флаг пометки
на удаление';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkPlaces"."Name" IS 'Название рабочего
места';
-- ddl-end --
COMMENT ON COLUMN "WorkshopInformation"."WorkPlaces"."Description" IS 'Подробное
описание';
-- ddl-end --
COMMENT ON COLUMN
"WorkshopInformation"."WorkPlaces"."ReferenceMeasuringInstrument" IS 'Эталонное
средство измерения';
-- ddl-end --
ALTER TABLE "WorkshopInformation"."WorkPlaces" OWNER TO postgres;
-- ddl-end --
117
-- object: "FK_MDLS_VMID_VM_ID" | type: CONSTRAINT --
-- ALTER TABLE "ElectricMeters"."Models" DROP CONSTRAINT IF EXISTS
"FK_MDLS_VMID_VM_ID" CASCADE;
ALTER TABLE "ElectricMeters"."Models" ADD CONSTRAINT "FK_MDLS_VMID_VM_ID" FOREIGN
KEY ("VerificationMethodId")
REFERENCES "Directories"."VerificationMethods" ("Id") MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
118
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
119
ALTER TABLE "WorkshopInformation"."WorkShifts" ADD CONSTRAINT
"FK_WSUSRID_USRS_ID" FOREIGN KEY ("UserId")
REFERENCES "WorkshopInformation"."Users" ("Id") MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
120