Почему при обмене через Конвертацию Данных удаляются все записи в регистре сведений приемника и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При настройке обмена данными между конфигурациями 1С с помощью «Конвертации данных 2.1» (КД) разработчики часто сталкиваются со специфическим поведением механизмов платформы при удалении данных. Особенно остро эта проблема проявляется при синхронизации регистров сведений разной структуры. В этой статье мы подробно разберем крайне неприятную ситуацию: почему при удалении или изменении одной записи в источнике в базе-приемнике может полностью очиститься весь регистр сведений, и рассмотрим практические способы решения этой проблемы.

Анализ исходной ситуации и симптомов проблемы

Рассмотрим классический сценарий. Настроен обмен (например, через нетиповой план обмена) между конфигурациями «Зарплата и управление персоналом» (ЗУП 3.1, выступает источником) и доработанной «Управление автотранспортом» (УАТ, выступает приемником). Из источника в приемник переносятся справочники и два регистра сведений:

  1. ДокументыФизическихЛиц
  2. КадроваяИсторияСотрудников

Для оптимизации записи в приемнике используется собственный алгоритм обмена. Из одной записи источника в приемнике должны сформироваться сразу две записи в разных регистрах. Для этого применяется стандартная функция Конвертации Данных ВыгрузитьПоПравилу().

Сложность возникает в следующем сценарии. Если в источнике удаляется или помечается на удаление документ, сделавший движения по регистру КадроваяИсторияСотрудников, в XML-файле обмена формируется следующий узел:


<НаборЗаписейРегистра Нпп="1" Тип="РегистрСведенийНаборЗаписей.уатСведенияОСотрудниках" ИмяПравила="уатСведенияОСотрудниках" ПустойНабор="true">
    <Отбор/>
    <СтрокиНабораЗаписей/>
</НаборЗаписейРегистра>

Обратите внимание на пустой тег <Отбор/> и параметр ПустойНабор="true". При чтении такого файла в базе-приемнике платформа 1С воспринимает это как команду: «записать пустой набор записей по регистру без ограничений отбора». В результате полностью очищается вся таблица регистра сведений уатСведенияОСотрудниках в приемнике!

При этом для второго регистра (ДокументыФизическихЛиц) аналогичная операция удаления генерирует корректный XML-пакет, где в теге <Отбор> четко прописаны ключевые поля удаляемой записи (Период, Физлицо, ВидДокумента), благодаря чему в приемнике стирается строго одна целевая запись.

Выясняем архитектурную причину сбоя

Разберемся, почему правила обмена ведут себя по-разному для двух визуально похожих регистров. Разгадка кроется в фундаментальном различии типов регистров сведений на стороне источника:

Поскольку в приемнике регистр сведений уатСведенияОСотрудниках является независимым (у него нет измерения «Регистратор»), при попытке выгрузить удаление подчиненного набора КД теряет связь по регистратору. Так как сопоставить измерения напрямую из зарегистрированного изменения невозможно, правила генерируют команду на запись пустого набора записей с пустым отбором. Платформа 1С при чтении такого набора полностью заменяет содержимое таблицы регистра сведений в соответствии с переданным отбором (а так как отбор пустой — стирается все).

Решение проблемы: три практических метода

Для устранения этой опасной проблемы и предотвращения случайной потери данных в базе-приемнике мы можем применить несколько подходов. Рассмотрим их подробно.

Вариант 1. Защита от полной очистки на стороне приемника (Рекомендуется)

Самый быстрый и безопасный способ обезопасить базу данных от полной очистки — поставить «предохранитель» на стороне загрузки (в приемнике). Если в файле обмена передается пустой набор записей и при этом у него отсутствует отбор, мы должны заблокировать его проведение.

Для этого в конфигурации «Конвертация данных» откроем ПКО (Правило конвертации объектов) для проблемного регистра сведений. В обработчике события «Перед загрузкой» напишем следующий код:


// Защита от затирания регистра при пустом отборе
Если ПустойНабор И Отбор.Количество() = 0 Тогда
    Отказ = Истина;
    ЗаписатьЛогСобытия("Попытка загрузки пустого набора записей без отбора заблокирована во избежание очистки регистра.", УровеньЖурналаРегистрации.Предупреждение);
КонецЕсли;

Этот простой шаг гарантирует, что база данных приемника больше никогда не будет полностью очищена из-за некорректно сформированных правил выгрузки на стороне источника.

Вариант 2. Программное формирование структуры набора при выгрузке (на стороне источника)

Чтобы удаление в источнике все-таки отрабатывало корректно и в приемнике удалялась нужная запись, мы должны вручную сформировать правильную структуру отбора на стороне источника.

Если обмен происходит в базах на платформе БСП (Библиотека стандартных подсистем) современных версий (начиная с 3.1.12), то стандартная процедура ВыгрузитьРегистр() была упразднена. Вместо нее разработчики БСП добавили экспортную функцию ВыгрузкаРегистра().

Синтаксис актуальной функции БСП выглядит так:


Функция ВыгрузкаРегистра(НаборЗаписейДляВыгрузки, Правило = Неопределено, ВходящиеДанные = Неопределено, НеВыгружатьОбъектыСвойствПоСсылкам = Ложь, ИмяПКО = "") Экспорт

Мы можем программно перехватить выгрузку набора записей. Вместо передачи стандартного набора (который при удалении документа-регистратора пустой и не имеет структуры) мы вручную передадим структуру с ключами "Отбор" и "Строки". Напишем этот алгоритм в правилах выгрузки данных (ПВД) или в обработчиках событий ПКО регистра:


// Формируем структуру имитации набора записей для КД
СтруктураНабора = Новый Структура;

// Задаем отбор по ключевым измерениям, которые однозначно идентифицируют запись
СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("Сотрудник", ТекущийСотрудник);
СтруктураОтбора.Вставить("Период", ТекущийПериод);

СтруктураНабора.Вставить("Отбор", СтруктураОтбора);
// Передаем пустую таблицу значений для удаления записи по этому отбору
СтруктураНабора.Вставить("Строки", Новый ТаблицаЗначений);

// Выгружаем данные по правилу обмена через актуальный метод БСП
ВыгрузкаРегистра(СтруктураНабора, , , , "уатСведенияОСотрудниках");

В этом случае в XML-файл запишется корректный узел с отбором по конкретному сотруднику и периоду, и в приемнике очистится только запись по данному сотруднику, а не вся таблица.

Вариант 3. Опосредованное удаление через параметры регистратора

Еще один надежный способ синхронизации подчиненного и независимого регистра — перенос логики удаления на уровень документа-регистратора.

Поскольку подчиненный регистр всегда очищается при отмене проведения или удалении своего документа-регистратора, мы можем передавать информацию об удаляемых записях внутри XML-пакета самого документа:

  1. В ПКО документа-регистратора (например, ПриемНаРаботу) в обработчике события «Перед выгрузкой» проверяем режим работы документа. Если документ удаляется или отменяется проведение, собираем данные его движений до момента очистки и помещаем их во временную структуру.
  2. Передаем эти данные через коллекцию ПараметрыОбъекта:
    
    // В обработчике "Перед выгрузкой" документа-регистратора
    ПараметрыОбъекта = Новый Соответствие;
    ПараметрыОбъекта.Вставить("СотрудникДляУдаления", СсылкаНаСотрудника);
    ПараметрыОбъекта.Вставить("ПериодДляУдаления", ДатаДокумента);
    
  3. В базе-приемнике в ПКО этого же документа в обработчике события «После загрузки» принимаем эти параметры и программно удаляем записи из независимого регистра приемника:
    
    // В обработчике "После загрузки" документа-приемника
    Если ПараметрыОбъекта <> Неопределено Тогда
        СотрудникУд = ПараметрыОбъекта.Получить("СотрудникДляУдаления");
        ПериодУд = ПараметрыОбъекта.Получить("ПериодДляУдаления");
        
        Если ЗначениеЗаполнено(СотрудникУд) Тогда
            // Программное удаление записи из независимого регистра сведений
            НаборЗаписей = РегистрыСведений.уатСведенияОСотрудниках.СоздатьНаборЗаписей();
            НаборЗаписей.Отбор.Сотрудник.Установить(СотрудникУд);
            НаборЗаписей.Отбор.Период.Установить(ПериодУд);
            НаборЗаписей.Записать(); // Записываем пустой набор с отбором, стирая запись
        КонецЕсли;
    КонецЕсли;
    

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

Применяя комбинацию Варианта 1 (для гарантированной безопасности данных от полной очистки) и Варианта 2 или 3 (для реализации логики точечного удаления), вы сможете построить стабильный и отказоустойчивый обмен данными между любыми конфигурациями 1С.

← На главную