Перейти к основному содержимому
Версия: 7.0

Rules: integration

Правила: импорт данных (IMPORT)

  1. Прежде чем работать с IMPORT, ассистент ОБЯЗАН определить элементы в следующем порядке:

    • модуль и пространство имён, владеющие потоком импорта
    • целевые классы, которые будут создаваться или обновляться
    • промежуточные (staging) свойства, используемые при импорте
    • действия импорта
    • формы импорта, если данные иерархичны
  2. Ассистент ОБЯЗАН осознанно выбирать стиль импорта:

    • плоские файлы (CSV, XLS, DBF, TABLE) -> предпочесть IMPORT ... TO или FIELDS
    • вложенные JSON / XML, структуры родитель-потомок, пространства имён или сопоставление EXTID -> предпочесть импорт через форму
    • построчные интеграционные ответы -> предпочесть FIELDS ... DO
  3. Для плоских импортов, требующих валидации, дедупликации, многопроходной обработки или постобработки, ассистенту СЛЕДУЕТ сначала складывать данные в LOCAL-свойства, обычно по INTEGER-строке, а затем обрабатывать их отдельным проходом FOR imported(INTEGER i).

  4. Ассистенту СЛЕДУЕТ использовать FIELDS ... DO, когда импортируемые значения используются лишь однажды и введение переиспользуемых локальных свойств добавило бы шум.

  5. Ассистенту СЛЕДУЕТ указывать сопоставление колонок явно, когда внешний шаблон фиксирован или разрежен.

    Последовательное сопоставление без явных идентификаторов колонок допустимо только когда сам порядок колонок является согласованным интерфейсом.

  6. Для импорта через форму ассистент ОБЯЗАН объявить выделенную форму импорта до использования.

    Форма ОБЯЗАНА использовать один объект на группу объектов с числовыми или конкретными пользовательскими классами.

    Форме СЛЕДУЕТ отражать внешнюю структуру через:

    • FILTERS для связей родитель-потомок
    • EXTID, FORMEXTID, группы и ATTR только там, где этого требует внешняя схема

    Ассистент ОБЯЗАН помнить, что импорт в форму отменяет ожидающие изменения импортируемых свойств формы в текущей сессии.

  7. Ассистент ОБЯЗАН явно выбирать опции формата, когда от них зависит внешний контракт:

    • HEADER / NOHEADER
    • SHEET
    • CHARSET

    Ассистенту СЛЕДУЕТ предпочитать HEADER для стабильных шаблонов CSV / XLS, потому что NOHEADER может незаметно сопоставить отсутствующие или неверно типизированные колонки в NULL.

  8. Ассистент ОБЯЗАН валидировать ссылочные бизнес-ключи до создания или обновления постоянных объектов.

    Типичные ключи в этом проекте — id, number, коды партнёров или товаров и внешние ссылки.

    Каждая ссылка ДОЛЖНА проверяться в отдельном FOR через GROUP SUM 1 BY по импортируемым значениям ключей.

    По возможности ассистенту НЕ СЛЕДУЕТ записывать разрешённые ссылки в отдельный LOCAL до основной логики импорта.

    Отсутствующие мастер-данные или некорректные данные ДОЛЖНЫ останавливать импорт или выдавать понятную ошибку.

  9. Ассистенту СЛЕДУЕТ разделять сырой импорт и доменное разрешение:

    • сначала разобрать файл или данные в локальные свойства или форму импорта
    • затем проверить ссылки, такие как товар, партнёр, статус, тип или другие справочники
    • только потом создавать или обновлять доменные объекты
  10. Для запускаемых пользователем пакетных импортов и внешних интеграций ассистенту СЛЕДУЕТ изолировать сохранение в NEWSESSION и СЛЕДУЕТ выполнять APPLY; после доменных записей одного импорта.

    Три правила сессий изменений задевают любой импорт, поэтому они приведены здесь, а не оставлены на второй запрос:

    • буфер, заполненный в верхней сессии, доходит до новой только через NESTED — в операторе либо в самом объявлении DATA LOCAL NESTED, — и не доходит вовсе под NEWSQL, который не переносит ничего;
    • после APPLY; ассистент ОБЯЗАН проверить canceled(), прежде чем считать импорт состоявшимся;
    • ошибку, поднятую самим APPLY, платформа уже показала интерактивному пользователю, поэтому интерактивный импорт НЕ ДОЛЖЕН сообщать её повторно; импорт из API или фоновый ОБЯЗАН сообщить её сам — через applyMessage() или исключение.

    Остальные — в статье про сессии изменений: lsfusion_get_guidance(rules='logic').

  11. Ассистент НЕ ДОЛЖЕН частично сохранять неудавшийся импорт молча. Для ошибок, которые ассистент обнаруживает сам (отсутствующие ссылки, некорректные данные, валидация до APPLY), ему СЛЕДУЕТ использовать MESSAGE, RETURN, throwException или явный флаг неудачи, согласованно с вызывающей стороной:

    • интерактивный импорт -> MESSAGE
    • API или фоновая интеграция -> исключение или явное состояние неудачи
  12. Для импортов-синхронизаций «создать-или-обновить» ассистент ОБЯЗАН разделять создание объектов и обновление свойств.

    Ассистент ОБЯЗАН делать один отдельный проход, только создающий недостающие объекты. FOR — один из способов его записать; множественная форма NEW ... WHERE ... TO создает объект на каждый подходящий набор одной операцией и предпочтительна везде, где подходит.

    Если импортируемые значения ключей могут быть неуникальны, проход создания СЛЕДУЕТ итерировать по сгруппированным ключам через GROUP SUM ... BY, а не по сырым импортируемым строкам.

    Затем ассистент ОБЯЗАН обновить свойства найденных объектов вторым отдельным проходом — прямое <- ... WHERE меняет все подходящие наборы разом, а FOR нужен только там, где тело делает то, чего множественное изменение не умеет.

    Ассистент НЕ ДОЛЖЕН смешивать создание объектов и обновление свойств в одном проходе для импортов-синхронизаций.

    Если требуется полная синхронизация, ассистенту СЛЕДУЕТ добавить явный шаг удаления.

  13. Если LOCAL-свойства промежуточного хранения используются только в одном действии импорта, ассистент ОБЯЗАН объявлять их внутри этого действия.

    Ассистенту НЕ СЛЕДУЕТ выносить такие LOCAL-свойства на уровень модуля без необходимости.

    Исключение: LOCAL-свойство можно объявить вне действия только когда оно должно использоваться формой импорта или переиспользоваться несколькими связанными действиями.

Правила: экспорт данных (EXPORT)

Выбор источника экспорта

Данные экспортируются оператором EXPORT.

  1. Экспорт списка свойств (EXPORT FROM ...) используется, когда результат — одна плоская таблица колонок и структура выгрузки не совпадает ни с одной формой.

  2. Экспорт формы (EXPORT formName ...) используется, когда выгрузка повторяет уже существующую форму или когда в результате нужна иерархия групп объектов. Иерархия сохраняется только в JSON и XML; в плоских форматах каждая группа объектов дает отдельный файл, поэтому для них приемники перечисляются по группам в блоке TO — только для нужных групп: не попавшая в список группа просто не экспортируется.

  3. Форму, созданную исключительно ради выгрузки, следует объявлять рядом с действием экспорта и не добавлять в навигатор.

Явное указание того, что влияет на результат

  1. Формат следует указывать явно даже тогда, когда нужен JSON: умолчание делает выгрузку зависимой от того, что читающий код помнит про умолчание.

  2. Условие WHERE следует указывать явно. Без него условием считается дизъюнкция всех экспортируемых свойств, то есть в выгрузку попадут наборы объектов, у которых заполнено хотя бы одно поле, — это почти никогда не совпадает с нужным набором строк.

  3. Идентификаторы колонок следует задавать явно (columnId = expr). Умолчание expr1, ..., exprN привязывает имена полей во внешнем формате к порядку выражений, поэтому вставка колонки в середину списка молча меняет контракт выгрузки.

  4. ORDER следует указывать явно всегда, когда принимающая сторона зависит от порядка строк. Выражения в нем произвольны и не обязаны входить в список экспортируемых — выражение сортировки добавляется во внутренний запрос скрытой колонкой и в результат не попадает, — поэтому колонку следует включать в выгрузку только тогда, когда она нужна получателю, а не ради того, чтобы по ней отсортировать.

  5. В иерархических форматах свойство со значением NULL пропускается в записи (в JSON отсутствует ключ, в XML — элемент), а плоские форматы (CSV, XLS, XLSX, DBF) сохраняют колонку и записывают пустую ячейку. Поэтому в JSON отсутствующий ключ означает NULL, а не сбой выгрузки (для свойств формы со SHOWIF включение определяется значением SHOWIF: не-NULL значение может быть пропущено, а NULL — выгружено).

  6. Когда одной выгрузкой возвращается несколько скалярных значений (результаты проверок, диагностика), отдельные колонки EXPORT FROM a = ..., b = ... предпочтительнее одной склеенной строки: NULL убирает только свой ключ, тогда как в конкатенации через + он обнуляет весь результат. Чтобы ключ присутствовал всегда, значение оборачивается в OVERRIDE ..., <умолчание> (при экспорте формы можно использовать опцию свойства EXTNULL). Выгрузка выражений без параметров сохраняет свою единственную запись, даже когда все значения NULL; для строк, порождаемых параметрами выгрузки, умолчание WHERE (дизъюнкция) выбрасывает полностью NULL-запись — условие WHERE следует задать явно или добавить константную колонку.

Опции формата

  1. Опции, у которых умолчание отличается для разных форматов, следует задавать явно: наличие строки заголовка (HEADER / NOHEADER) в CSV, XLS, XLSX, разделитель CSV (по умолчанию ;) и кодировку (CHARSET, по умолчанию UTF-8, а для DBFCP1251).

  2. NOESCAPE в CSV допустимо использовать только тогда, когда разделитель гарантированно не встречается в данных; в остальных случаях следует оставлять ESCAPE.

  3. Кодировку следует определять требованиями принимающей стороны, а не значением по умолчанию: получатели DBF-файлов обычно ожидают однобайтовую кодировку, отличную от UTF-8.

Приемник результата

  1. Свойство-приемник в TO следует объявлять локальным для действия экспорта и файлового класса (FILE, RAWFILE, JSONFILE), а не использовать общее свойство: одно свойство, разделяемое несколькими выгрузками, делает результат зависящим от порядка выполнения.

  2. Умолчание System.exportFile допустимо только для отладочных и разовых выгрузок.

  3. При экспорте формы в плоский формат приемники следует перечислять для всех выгружаемых групп объектов; группа объектов без имени называется root.

Передача результата

  1. Действие следует разделять на подготовку данных, собственно EXPORT и передачу файла получателю — записью в файловую систему, отправкой во внешнюю систему или сохранением в свойстве. Такое разделение позволяет повторно использовать выгрузку с разными способами доставки.

  2. Для регулярных выгрузок формирование файла следует делать в отдельном действии без взаимодействия с пользователем, чтобы его можно было вызывать и с формы, и по расписанию.

Примеры

Первый показывает форму со списком свойств: плоский результат, чья структура не совпадает ни с одной формой, с алиасами колонок, отбором в 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;
}