Работа с локальными справочниками#
В DataSpace имеется возможность создавать локальные справочники и ссылаться на них из доменных сущностей. Таким образом можно иметь готовые данные, например, категории клиентов, города, офисы и другие.
Наполнение справочников в хранилище происходит на этапе применения Liquibase-скриптов изменения модели.
Разметка данных#
Для добавления справочников в проект необходимо пометить требуемые классы признаком is-dictionary и создать файлы справочников.
Для файлов справочников должна быть создана отдельная папка. По умолчанию используется подпапка model/dictionary, где model — папка с файлами модели и статусов. Папку для справочников можно переопределить с помощью свойства file: <import file="nameDir" type="IMPORT"/>.
Разметка справочников подчиняется следующим правилам:
Справочная сущность должна быть помечена свойством
is-dictionaryтега<class>. Этот признак должен стоять на корне наследования. Признак можно опустить на классах-потомках.Размечать на классе можно только поля, коллекции примитивов, индексы.
Ссылка на справочник может быть определена для любого агрегата.
Пример описания справочника:
<model model-name="myModel" version="1.0.0-SNAPSHOT">
<class name="City" label="Город" is-dictionary="true">
<property name="code" type="String" label="Код" mandatory="true"/>
<property name="name" type="String" label="Наименование" mandatory="true"/>
<property name="offices" type="Office" label="Офисы" collection="set" mappedBy="city"/>
<property name="identification" type="Identification"/>
</class>
<class name="Identification" embeddable="true">
<property name="ecs" type="String" label="Идентификатор в единой система"/>
<property name="kladr" type="String" label="Идентификатор в системе КЛАДР"/>
</class>
</model>
Для справочников не может быть иной стратегии заполнения идентификатора кроме ручной, то есть <id category="MANUAL"/>. Если вы не укажете категорию, то она заполнится этим значением по умолчанию.
Для справочников можно указать индексы. Разметка не отличается от общих правил.
Начиная с версии DataSpace 1.11.0 добавилась возможность указания тега parent для связи дочернего/родительского справочника. Указание
тега приведет к каскадному удалению дочерних справочных сущностей при удалении родительской.
Пример:
<model>
<class name="Region" is-dictionary="true">
<property name="name" type="String"/>
<property name="city" type="City" collection="set" mappedBy="region"/>
</class>
<class name="City" is-dictionary="true">
<property name="name" type="String"/>
<property name="region" type="Region" parent="true"/>
</class>
</model>
В примере выше при удалении сущности Region все связанные с ней сущности City также будут удалены.
Структура справочника#
Структура данных задается в формате JSON. Для описания данных справочников необходимо выполнить следующие шаги:
В папке, в которой лежит описание модели (model.xml), создать папку
dictionary. Если это имя папки недопустимо, его необходимо переопределить, указав относительный путь к папке в файле model.xml:<import type="DICTIONARY_GENERATOR" file="./dictionaryFolder"/>Расположить в этой папке файлы справочников. Принадлежность файлов к справочным данным определяется по расширению файла. JSON-файлы должны называться *.json. Структурировать справочные данные можно по файлам и папкам, как показано на изображении ниже.

Описания данных в формате JSON должно включать в себя следующие поля:
type: имя типа. Это название справочника из атрибутаnameтегаclassфайла model.xml. Полеtype— опционально. Если его не указать, то тип определяется из названия файла <Имя справочника>.json.objects: массив с описанием данных. Объект в массиве objects подчиняется стандартным правилам json-описания объектов.
Пример описания данных для справочника «Область» из описания справочников выше:
{
"type": "City",
"objects": [
{
"id": "1",
"code": "RND",
"name": "Ростов-на-Дону",
"identification": {
"ecs": "22r",
"kladr": "32"
}
},
{
"id": "2",
"code": "MSK",
"name": "Москва",
"identification": {
"ecs": "23",
"kladr": "3"
}
},
{
"id": "3",
"code": "SPB",
"name": "Санкт-Петербург",
"identification": {
"ecs": "02pit",
"kladr": "320"
}
}
]
}
Спецификация формата#
При разработке справочников необходимо придерживаться следующих правил:
Для каждого справочника должен быть определен идентификатор, определенный через свойство
id. Если идентификатор не будет указан хотя бы на одном объекте, то будет сгенерирована ошибка типаObjectWithNoIdExceptionс указанием названия справочника с отсутствующим идентификатором.Из справочника можно ссылаться только на другой справочник и нельзя сослаться на сущность. Ссылка на другой справочник создается только через валидный идентификатор. Если указанный объект справочника не найден, будет сгенерирована ошибка
DictionaryConsistencyExceptionс уточнением того, справочник с какимidне удалось обнаружить.Можно использовать embedded-классы.
Для реализации связи между справочниками Справочник 1 должен включать в себя идентификаторы позиций из Справочника 2. В примере ниже это поле «город» (
city):{ "type": "Office", "objects": [ { "id": "1", "city": "2", "code": "Kosmonavtov27", "name": "Офис на Космонавтов 27" } ] }Ниже показан пример значения, на которое указывает ссылка:
{ "type": "City", "objects": [ { "id": "1", "code": "RND", "name": "Ростов-на-Дону" }, { "id": "2", "code": "MSK", "name": "Москва" } ] }Идентификаторы каждого справочника должны быть уникальны.
При создании справочника поля, имеющие null-значения, можно просто не описывать в данных. При обновлении поля значением «null» необходимо присвоить значению поля величину null. Значение указывается без кавычек. Пример:
{ "type": "City", "objects": [ { "id": "2", "code": "MSK", "name": null } ] }Поле
nameбудет иметь значение «null».Начиная с версии DataSpace 1.11.0 добавлена возможность указания максимального размера файла с данными справочников. Сделано это для предотвращения превышения размера вектора изменений данных при передаче через транспортную систему. Каждый файл обрабатывается отдельной транзакцией. Таким образом, регулируя размер файла, можно регулировать размер данных транзакции и размер вектора изменений. Размер файла регулируется параметром плагина сборки
maxDictionaryFileSize. По умолчанию значение параметра — 512 Кб.При возникновении ошибки с текстом В справочных данных присутствует объект, данные для обновления или для отката обновления которого целиком не могут быть размещены в файле заданного размера. Необходимо увеличить размер файла. Необходимо увеличить значение параметра
maxDictionaryFileSize, при этом проверив работоспособность StandIn с вектором изменения получающегося размера, при наличии интеграции со StandIn. При тестировании версии необходимо убедиться, что обновление справочника успешно выполняется на стенде, соответствующем промышленной конфигурации (включая настройки StandIn и Kafka).При задании связей между справочниками, образующих циклические ссылки между их записями, для исполнения их обновления в одной транзакции и отсутствию возможности поделить такие данные на независимые порции, все такие записи помещаются в один файл независимо от параметра максимального размера файла, что может привести к ошибкам при передаче вектора изменений. Следует учитывать это ограничение при формировании циклически связанных структур. В данной ситуации в логах сборки артефакта модели будет предупреждение с текстом «Файл части справочника не вписывается в размер, заданный параметром „maxDictionaryFileSize“, необходимо провести дополнительное тестирование загрузки справочника в условиях, приближенных к промышленной эксплуатации».
Алгоритм работы#
При первом формировании справочных данных происходит формирование скриптов Liquibase с наполнением хранилища данными справочников. Также произойдет сохранение текущих данных в папку model/dictionary.
Сохранение данных необходимо для расчета изменений справочников в дальнейшем. При дальнейшем развитии справочников анализируются новые объекты и сравниваются с сохраненной информацией от предыдущей итерации изменений. Очередные Liquibase-скрипты наполняются обновлением только той информации, которая изменилась. То есть будут вставлены только вновь появившиеся справочные данные и обновлены те, что изменились.
При формировании Liquibase скриптов осуществляется проверка справочных данных, заполненных в json файлах на валидность.
В случае, если данные не валидны, возникнет исключение с описанием проблемы.
Если необходимо отключить проверку, то можно воспользоваться параметром плагина enableDictionaryDataCheck. По умолчанию
параметр имеет значение true.
Внимание!
Удаление справочника недопустимо, ни один справочник из предыдущей итерации (анализируется id) не должен исчезнуть.
Обновление справочных данных#
Справочные данные можно обновить. Разрешается обновлять все поля кроме id. Изменение id равноценно удалению справочных данных, что запрещено (см. выше блок «Внимание»). Для обновления данных рассчитывается дельта изменений и обновлению подвергаются лишь изменившиеся данные. Обновление осуществляется простым изменением текущих данных справочников.
Обязательные поля справочных классов#
При добавлении в класс-справочник обязательности на существующее поле или при добавлении нового обязательного поля может
возникнуть ситуация, при которой ранее созданные справочные данные не смогут быть применены к новой структуре.
При последовательном накате скрипта на БД поведение будет штатным. Однако, если накатывать скрипт, например, на пустую БД
или накатывать сразу несколько версий, одна из которых имеет данные с пустыми значениями обязательного поля, то возникнет
ошибка Отсутствуют обязательные к заполнению поля [<перечень полей>].
Проблему можно решить двумя способами:
Отказаться от использования обязательных полей в справочниках, принимая во внимание, что данные для наполнения справочников готовятся разработчиком и контролируются как на этапе разработки, так и при тестировании;
Провести ручную корректировку предыдущих справочных данных. Справочные данные, используемые liquibase скриптом при установке версии, находятся в файлах
changelogFiles/content-*.json. Необходимо найти все записи справочников, в которых не заполнены значения обязательных полей, и дозаполнить их. Важно, чтобы перед установкой версии с обязательными полями были предварительно установлены все предыдущие версии.