Rules: integration
Правила: импорт данных (IMPORT)
-
Прежде чем работать с
IMPORT, ассистент ОБЯЗАН определить элементы в следующем порядке:- модуль и пространство имён, владеющие потоком импорта
- целевые классы, которые будут создаваться или обновляться
- промежуточные (staging) свойства, используемые при импорте
- действия импорта
- формы импорта, если данные иерархичны
-
Ассистент ОБЯЗАН осознанно выбирать стиль импорта:
- плоские файлы (
CSV,XLS,DBF,TABLE) -> предпочестьIMPORT ... TOилиFIELDS - вложенные
JSON/XML, структуры родитель-потомок, пространства имён или сопоставлениеEXTID-> предпочесть импорт через форму - построчные интеграционные ответы
-> предпочесть
FIELDS ... DO
- плоские файлы (
-
Для плоских импортов, требующих валидации, дедупликации, многопроходной обработки или постобработки, ассистенту СЛЕДУЕТ сначала складывать данные в
LOCAL-свойства, обычно поINTEGER-строке, а затем обрабатывать их отдельным проходомFOR imported(INTEGER i). -
Ассистенту СЛЕДУЕТ использовать
FIELDS ... DO, когда импортируемые значения используются лишь однажды и введение переиспользуемых локальных свойств добавило бы шум. -
Ассистенту СЛЕДУЕТ указывать сопоставление колонок явно, когда внешний шаблон фиксирован или разрежен.
Последовательное сопоставление без явных идентификаторов колонок допустимо только когда сам порядок колонок является согласованным интерфейсом.
-
Для импорта через форму ассистент ОБЯЗАН объявить выделенную форму импорта до использования.
Форма ОБЯЗАНА использовать один объект на группу объектов с числовыми или конкретными пользовательскими классами.
Форме СЛЕДУЕТ отражать внешнюю структуру через:
FILTERSдля связей родитель-потомокEXTID,FORMEXTID, группы иATTRтолько там, где этого требует внешняя схема
Ассистент ОБЯЗАН помнить, что импорт в форму отменяет ожидающие изменения импортируемых свойств формы в текущей сессии.
-
Ассистент ОБЯЗАН явно выбирать опции формата, когда от них зависит внешний контракт:
HEADER/NOHEADERSHEETCHARSET
Ассистенту СЛЕДУЕТ предпочитать
HEADERдля стабильных шаблоновCSV/XLS, потому чтоNOHEADERможет незаметно сопоставить отсутствующие или неверно типизированные колонки вNULL. -
Ассистент ОБЯЗАН валидировать ссылочные бизнес-ключи до создания или обновления постоянных объектов.
Типичные ключи в этом проекте —
id,number, коды партнёров или товаров и внешние ссылки.Каждая ссылка ДОЛЖНА проверяться в отдельном
FORчерезGROUP SUM 1 BYпо импортируемым значениям ключей.По возможности ассистенту НЕ СЛЕДУЕТ записывать разрешённые ссылки в отдельный
LOCALдо основной логики импорта.Отсутствующие мастер-данные или некорректные данные ДОЛЖНЫ останавливать импорт или выдавать понятную ошибку.
-
Ассистенту СЛЕДУЕТ разделять сырой импорт и доменное разрешение:
- сначала разобрать файл или данные в локальные свойства или форму импорта
- затем проверить ссылки, такие как товар, партнёр, статус, тип или другие справочники
- только потом создавать или обновлять доменные объекты
-
Для запускаемых пользователем пакетных импортов и внешних интеграций ассистенту СЛЕДУЕТ изолировать сохранение в
NEWSESSIONи СЛЕДУЕТ выполнятьAPPLY;после доменных записей одного импорта.Три правила сессий изменений задевают любой импорт, поэтому они приведены здесь, а не оставлены на второй запрос:
- буфер, заполненный в верхней сессии, доходит до новой
только через
NESTED— в операторе либо в самом объявленииDATA LOCAL NESTED, — и не доходит вовсе подNEWSQL, который не переносит ничего; - после
APPLY;ассистент ОБЯЗАН проверитьcanceled(), прежде чем считать импорт состоявшимся; - ошибку, поднятую самим
APPLY, платформа уже показала интерактивному пользователю, поэтому интерактивный импорт НЕ ДОЛЖЕН сообщать её повторно; импорт из API или фоновый ОБЯЗАН сообщить её сам — черезapplyMessage()или исключение.
Остальные — в статье про сессии изменений:
lsfusion_get_guidance(rules='logic'). - буфер, заполненный в верхней сессии, доходит до новой
только через
-
Ассистент НЕ ДОЛЖЕН частично сохранять неудавшийся импорт молча. Для ошибок, которые ассистент обнаруживает сам (отсутствующие ссылки, некорректные данные, валидация до
APPLY), ему СЛЕДУЕТ использоватьMESSAGE,RETURN,throwExceptionили явный флаг неудачи, согласованно с вызывающей стороной:- интерактивный импорт ->
MESSAGE - API или фоновая интеграция -> исключение или явное состояние неудачи
- интерактивный импорт ->
-
Для импортов-синхронизаций «создать-или-обновить» ассистент ОБЯЗАН разделять создание объектов и обновление свойств.
Ассистент ОБЯЗАН делать один отдельный проход, только создающий недостающие объекты.
FOR— один из способов его записать; множественная формаNEW ... WHERE ... TOсоздает объект на каждый подходящий набор одной операцией и предпочтительна везде, где подходит.Если импортируемые значения ключей могут быть неуникальны, проход создания СЛЕДУЕТ итерировать по сгруппированным ключам через
GROUP SUM ... BY, а не по сырым импортируемым строкам.Затем ассистент ОБЯЗАН обновить свойства найденных объектов вторым отдельным проходом — прямое
<- ... WHEREменяет все подходящие наборы разом, аFORнужен только там, где тело делает то, чего множественное изменение не умеет.Ассистент НЕ ДОЛЖЕН смешивать создание объектов и обновление свойств в одном проходе для импортов-синхронизаций.
Если требуется полная синхронизация, ассистенту СЛЕДУЕТ добавить явный шаг удаления.
-
Если
LOCAL-свойства промежуточного хранения используются только в одном действии импорта, ассистент ОБЯЗАН объявлять их внутри этого действия.Ассистенту НЕ СЛЕДУЕТ выносить такие
LOCAL-свойства на уровень модуля без необходимости.Исключение:
LOCAL-свойство можно объявить вне действия только когда оно должно использоваться формой импорта или переиспользоваться несколькими связанными действиями.
Правила: экспорт данных (EXPORT)
Выбор источника экспорта
Данные экспортируются оператором EXPORT.
-
Экспорт списка свойств (
EXPORT FROM ...) используется, когда результат — одна плоская таблица колонок и структура выгрузки не совпадает ни с одной формой. -
Экспорт формы (
EXPORT formName ...) используется, когда выгрузка повторяет уже существующую форму или когда в результате нужна иерархия групп объектов. Иерархия сохраняется только в JSON и XML; в плоских форматах каждая группа объектов дает отдельный файл, поэтому для них приемники перечисляются по группам в блокеTO— только для нужных групп: не попавшая в список группа просто не экспортируется. -
Форму, созданную исключительно ради выгрузки, следует объявлять рядом с действием экспорта и не добавлять в навигатор.
Явное указание того, что влияет на результат
-
Формат следует указывать явно даже тогда, когда нужен JSON: умолчание делает выгрузку зависимой от того, что читающий код помнит про умолчание.
-
Условие
WHEREследует указывать явно. Без него условием считается дизъюнкция всех экспортируемых свойств, то есть в выгрузку попадут наборы объектов, у которых заполнено хотя бы одно поле, — это почти никогда не совпадает с нужным набором строк. -
Идентификаторы колонок следует задавать явно (
columnId = expr). Умолчаниеexpr1, ...,exprNпривязывает имена полей во внешнем формате к порядку выражений, поэтому вставка колонки в середину списка молча меняет контракт выгрузки. -
ORDERследует указывать явно всегда, когда принимающая сторона зависит от порядка строк. Выражения в нем произвольны и не обязаны входить в список экспортируемых — выражение сортировки добавляется во внутренний запрос скрытой колонкой и в результат не попадает, — поэтому колонку следует включать в выгрузку только тогда, когда она нужна получателю, а не ради того, чтобы по ней отсортировать. -
В иерархических форматах свойство со значением
NULLпропускается в записи (в JSON отсутствует ключ, в XML — элемент), а плоские форматы (CSV, XLS, XLSX, DBF) сохраняют колонку и записывают пустую ячейку. Поэтому в JSON отсутствующий ключ означаетNULL, а не сбой выгрузки (для свойств формы соSHOWIFвключение определяется значениемSHOWIF: не-NULLзначение может быть пропущено, аNULL— выгружено). -
Когда одной выгрузкой возвращается несколько скалярных значений (результаты проверок, диагностика), отдельные колонки
EXPORT FROM a = ..., b = ...предпочтительнее одной склеенной строки:NULLубирает только свой ключ, тогда как в конкатенации через+он обнуляет весь результат. Чтобы ключ присутствовал всегда, значение оборачивается вOVERRIDE ..., <умолчание>(при экспорте формы можно использовать опцию свойстваEXTNULL). Выгрузка выражений без параметров сохраняет свою единственную запись, даже когда все значенияNULL; для строк, порождаемых параметрами выгрузки, умолчаниеWHERE(дизъюнкция) выбрасывает полностьюNULL-запись — условиеWHEREследует задать явно или добавить константную колонку.
Опции формата
-
Опции, у которых умолчание отличается для разных форматов, следует задавать явно: наличие строки заголовка (
HEADER/NOHEADER) в CSV, XLS, XLSX, разделитель CSV (по умолчанию;) и кодировку (CHARSET, по умолчаниюUTF-8, а для DBF —CP1251). -
NOESCAPEв CSV допустимо использовать только тогда, когда разделитель гарантированно не встречается в данных; в остальных случаях следует оставлятьESCAPE. -
Кодировку следует определять требованиями принимающей стороны, а не значением по умолчанию: получатели DBF-файлов обычно ожидают однобайтовую кодировку, отличную от
UTF-8.
Приемник результата
-
Свойство-приемник в
TOследует объявлять локальным для действия экспорта и файлового класса (FILE,RAWFILE,JSONFILE), а не использовать общее свойство: одно свойство, разделяемое несколькими выгрузками, делает результат зависящим от порядка выполнения. -
Умолчание
System.exportFileдопустимо только для отладочных и разовых выгрузок. -
При экспорте формы в плоский формат приемники следует перечислять для всех выгружаемых групп объектов; группа объектов без имени называется
root.
Передача результата
-
Действие следует разделять на подготовку данных, собственно
EXPORTи передачу файла получателю — записью в файловую систему, отправкой во внешнюю систему или сохранением в свойстве. Такое разделение позволяет повторно использовать выгрузку с разными способами доставки. -
Для регулярных выгрузок формирование файла следует делать в отдельном действии без взаимодействия с пользователем, чтобы его можно было вызывать и с формы, и по расписанию.
Примеры
Первый показывает форму со списком свойств: плоский результат, чья структура
не совпадает ни с одной формой, с алиасами колонок, отбором в WHERE
и явным ORDER. Второй показывает форму с формой: существующая форма
выгружается в иерархический формат, её внешний объект передан через OBJECTS.
exportShipments (Store store) {
LOCAL exportedFile = FILE ();
EXPORT CSV ';' HEADER FROM number = number(Shipment s), date = date(s), sum = sum(s)
WHERE store(s) = store AND shipped(s)
ORDER date(s)
TO exportedFile;
}
FORM exportOrders
OBJECTS st = Store
OBJECTS o = Order
PROPERTIES(o) number, date
FILTERS store(o) = st
;
exportOrders (Store store) {
LOCAL exportedFile = FILE ();
EXPORT exportOrders OBJECTS st = store JSON TO exportedFile;
}