Введение
Валидация данных — проверка данных на соответствие заданным условиям и ограничениям.
При обмене данными между разными информационными системами иногда возникает необходимость проверки данных на соответствие определенным критериям — это могут быть проверки на типы, диапазоны значений, заполненность полей, корректные связи между несколькими моделями и другое. С одной стороны, валидация это дополнительные затраты времени и ресурсов, с другой стороны — она позволяет значительно сократить время на последующую отладку и проверку при модификации обмена. По сути это Unit-тест, который проверяет результат выгрузки данных.
В данной статье описан один из подходов к валидации исходящих данных, на конкретном примере выгрузки из 1С для сайта.
Постановка задачи
Имеем базу оперативного учета компании, занимающейся оптово-розничной продажей. Необходимо подготовить и выгрузить данные в формате JSON и отправить их на сайт по протоколу HTTP.
Подготовка к реализации
Нужно выполнить две простые операции:
- сформировать необходимые данные в формате JSON
- передать данные на сайт
Если никак не проверять данные, то процесс скорее всего будет выглядеть так:
- Реализовали/Исправили на стороне 1С.
- Отправили данные на сайт.
- Подождали пока разработчики сайта за нас проверят данные, оказалось, что есть какие-то проблемы.
- Вернулись к п.1.
Важно, что при любом изменении логики или формата выгрузки, есть большая вероятность повторения этого циклического процесса исправления ошибок. И основная проблема даже не в том, что есть ошибки и мы их исправляем, а в том, что в процессе задействованы сразу несколько человек и процесс затягивается. Если бы разработчик 1С оперативно мог сам проверять результат, то он сразу бы исправил ошибки.
Сам процесс валидации можно разбить на два этапа:
- описание модели данных: типы, связи, обязательность
- проверка данных на основе описания
Реализация
Данные выгрузки представляют собой набор таблиц, которые связаны между собой. Для упрощения, будем считать, что это следующие таблицы: Товары, Остатки, Цены.
Для формирования JSON в 1С удобно представить набор таблиц в виде структуры, содержащей в себе массивы структур — каждая структура из массива описывает строку таблицы.
Выгрузка = Новый Структура();
Выгрузка.Вставить("Товары");
Выгрузка.Вставить("Остатки");
Выгрузка.Вставить("Цены");
Далее, необходимо объявить структуру, описывающую каждое поле таблицы, а также параметры которые мы собираемся контролировать. По значениям этих полей функция-валидатор будет проверять соответствующие поля. В нашем примере мы будем контролировать тип значения поля, допустимость равенства значения поля значению NULL (в каких-то случаях это допустимо, а в каких-то нет и это указывает на проблемы либо выборки данных, либо их хранения).
СтруктураПоля = Новый Структура("ИмяПоля, ТипПоля, ВозможенNULL, ОбязательноеЗаполнение");
Описание полей таблицы «Остатки» будет выглядеть следующим образом:
//Описываем поля
МассивПолейТаблицы = Новый Массив;
ПолеСтроки = ОписаниеСтруктурыПоля();
ПолеСтроки.ИмяПоля = "id";
ПолеСтроки.ТипПоля = Тип("Число");
ПолеСтроки.ВозможенNULL = Ложь;
ПолеСтроки.ОбязательноеЗаполнение = Истина;
МассивПолейТаблицы.Добавить(ПолеСтроки);
ПолеСтроки = ОписаниеСтруктурыПоля();
ПолеСтроки.ИмяПоля = "name";
ПолеСтроки.ТипПоля = Тип("Строка");
ПолеСтроки.ВозможенNULL = Ложь;
ПолеСтроки.ОбязательноеЗаполнение = Истина;
МассивПолейТаблицы.Добавить(ПолеСтроки);
ПолеСтроки = ОписаниеСтруктурыПоля();
ПолеСтроки.ИмяПоля = "article";
ПолеСтроки.ТипПоля = Тип("Строка");
ПолеСтроки.ВозможенNULL = Ложь;
ПолеСтроки.ОбязательноеЗаполнение = Ложь;
МассивПолейТаблицы.Добавить(ПолеСтроки);
Так как таблицы связаны по ключевым полям, то хочется проверять еще и логическую целостность выгруженных данных, например, проверить, что если мы выгружаем остаток по товару, то должны выгружать и сам товар. Для этого нам необходимо описать связи таблиц, чтобы функция валидации смогла их проверить. Проверка таблиц заключается в построении запроса по двум таблицам, с левым соединением по ключевым полям. В случае, если в результирующей таблице будут значения NULL в контролируемых полях присоединяемой таблицы, то это может означать нарушение логической целостности данных.
Структуру описания таблицы запишем следующим образом:
СтруктураТаблицы = Новый Структура("Наименование, МассивДанных, МассивПолейТаблицы, ПоляИдентифицирующиеЗапись"
, "", Новый Массив , Новый Массив, Новый Массив);
В целом, описание таблицы будет выглядеть так:
Функция СформироватьОписание_Товары(МассивДанных)
СтруктураВозврата = Новый Структура("СтруктураТаблицы, МассивСтруктурСвязей",
ОписаниеТаблицы(), Новый Массив);
//Описываем поля
МассивПолейТаблицы = Новый Массив;
ПолеСтроки = ОписаниеСтруктурыПоля();
ПолеСтроки.ИмяПоля = "id";
ПолеСтроки.ТипПоля = Тип("Число");
ПолеСтроки.ВозможенNULL = Ложь;
ПолеСтроки.ОбязательноеЗаполнение = Истина;
МассивПолейТаблицы.Добавить(ПолеСтроки);
ПолеСтроки = ОписаниеСтруктурыПоля();
ПолеСтроки.ИмяПоля = "name";
ПолеСтроки.ТипПоля = Тип("Строка");
ПолеСтроки.ВозможенNULL = Ложь;
ПолеСтроки.ОбязательноеЗаполнение = Истина;
МассивПолейТаблицы.Добавить(ПолеСтроки);
ПолеСтроки = ОписаниеСтруктурыПоля();
ПолеСтроки.ИмяПоля = "article";
ПолеСтроки.ТипПоля = Тип("Строка");
ПолеСтроки.ВозможенNULL = Ложь;
ПолеСтроки.ОбязательноеЗаполнение = Ложь;
МассивПолейТаблицы.Добавить(ПолеСтроки);
//Описание таблицы и связей
СтрокаСвязей = ОписаниеСвязейТаблиц();
СтрокаСвязей.НаименованиеТаблицы1 = "Товары";
СтрокаСвязей.НаименованиеТаблицы2 = "Остатки";
СтрокаСвязей.ИмяКлючаТаблицы1 = "id";
СтрокаСвязей.ИмяКлючаТаблицы2 = "prod_id";
СтрокаСвязей.СообщениеЕслиNULLЛевоеСоединение = "[Ошибка]Выгружены товары без остатков";
СтруктураВозврата.МассивСтруктурСвязей.Добавить(СтрокаСвязей);
СтрокаСвязей = ОписаниеСвязейТаблиц();
СтрокаСвязей.НаименованиеТаблицы1 = "Товары";
СтрокаСвязей.НаименованиеТаблицы2 = "Цены";
СтрокаСвязей.ИмяКлючаТаблицы1 = "id";
СтрокаСвязей.ИмяКлючаТаблицы2 = "prod_id";
СтрокаСвязей.СообщениеЕслиNULLЛевоеСоединение = "[Ошибка]Выгружены товары без цен";
СтруктураВозврата.МассивСтруктурСвязей.Добавить(СтрокаСвязей);
СтруктураВозврата.СтруктураТаблицы.Наименование = "Товары";
СтруктураВозврата.СтруктураТаблицы.МассивДанных = МассивДанных;
СтруктураВозврата.СтруктураТаблицы.МассивПолейТаблицы = МассивПолейТаблицы;
СтруктураВозврата.СтруктураТаблицы.ПоляИдентифицирующиеЗапись.Добавить("id");
Возврат СтруктураВозврата;
КонецФункции
Так как процедура проверки связей является универсальной, то в структуре, описывающей связь таблиц, сразу указывается текст ошибки, который будет записываться в лог выполнения, если возникнет ошибка.
Таким образом, мы описываем все таблицы нашей выгрузки и связи между ними, а затем «скармливаем» полученные данные и описание функции валидации, которая производит проверку и возвращает лог с ошибками.
Функция проверки таблиц выглядит следующим образом:
Функция ПроверитьТаблицы(ДанныеСтруктура)
СтруктураВозврата = Новый Структура("ОшибкиПроверкиПолей, ОшибкиПроверкиСвязей");
МассивТаблиц = Новый Массив;
РезультатПроверкаПолей = "";
МассивТаблиц.Добавить(СформироватьОписание_Товары(ДанныеСтруктура["Товары"]));
РезультатПроверки = ПроверитьДанныеПоПолямСтруктуры(МассивТаблиц[МассивТаблиц.ВГраница()].СтруктураТаблицы);
РезультатПроверкаПолей = РезультатПроверкаПолей
+ ?(РезультатПроверки = "", "", РезультатПроверки + Символы.ПС);
МассивТаблиц.Добавить(СформироватьОписание_Остатки(ДанныеСтруктура["Остатки"]));
РезультатПроверки = ПроверитьДанныеПоПолямСтруктуры(МассивТаблиц[МассивТаблиц.ВГраница()].СтруктураТаблицы);
РезультатПроверкаПолей = РезультатПроверкаПолей
+ ?(РезультатПроверки = "", "", РезультатПроверки + Символы.ПС);
МассивТаблиц.Добавить(СформироватьОписание_Цены(ДанныеСтруктура["Цены"]));
РезультатПроверки = ПроверитьДанныеПоПолямСтруктуры(МассивТаблиц[МассивТаблиц.ВГраница()].СтруктураТаблицы);
РезультатПроверкаПолей = РезультатПроверкаПолей
+ ?(РезультатПроверки = "", "", РезультатПроверки + Символы.ПС);
РезультатПроверкаСвязей = ПроверитьСвязиТаблиц(МассивТаблиц);
СтруктураВозврата.ОшибкиПроверкиПолей = РезультатПроверкаПолей;
СтруктураВозврата.ОшибкиПроверкиСвязей = РезультатПроверкаСвязей;
Возврат СтруктураВозврата;
КонецФункции
Заключение
Описанный подход к проверке данных не является каким-либо стандартом, а является лишь небольшим примером универсальной реализации валидатора данных, которым пользуемся мы при обмене данными между разными системами. Функция валидации не зависит от данных, для использования необходимо лишь подготовить описание данных и сами данные.
К статье прилагается обработка для демонстрации механизма проверки данных. Тестировалась на релизе платформы: 1С:Предприятие 8.3 (8.3.14.1993).