Почему очищается регистр «Контактная информация» после обмена данными и как это исправить?

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

При настройке обмена данными между двумя конфигурациями 1С разработчики часто сталкиваются со скрытыми угрозами, которые могут привести к частичной или полной потере информации в базе-приемнике. Одной из наиболее опасных и при этом «классических» проблем является внезапная очистка регистра сведений после выполнения сеанса синхронизации. Особенно ярко это проявляется на регистре КонтактнаяИнформация.

В этой статье мы подробно проанализируем, почему происходит полная очистка регистра, в чем заключается разница между обменом через XML и COM-соединение, и как написать надежный, отказоустойчивый код в КД 2.1 (Конвертация данных), который раз и навсегда решит эту проблему.

Причина №1: Запись пустого набора записей без установленных отборов

Для начала разберем внутреннюю механику работы платформы 1С с регистрами сведений. В отличие от справочников или документов, запись в регистр сведений всегда происходит порциями, которые называются наборами записей. Объект типа РегистрСведенийНаборЗаписей перед записью требует обязательной установки фильтров (отборов) по измерениям регистра.

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

  1. Система инициализирует объект набора записей для регистра КонтактнаяИнформация.
  2. Если правила конвертации свойств (ПКС) не настроены должным образом или ключевые параметры (такие как Объект, Тип или Вид) передаются пустыми, платформа не может сформировать точечный отбор.
  3. При вызове метода Записать() платформа перезаписывает данные регистра в соответствии с установленным отбором. Если отбор оказался пустым, 1С считает, что нужно перезаписать весь регистр пустым набором. В результате этого действия абсолютно все существующие записи в регистре базы-приемника мгновенно удаляются.

Эта ситуация часто усугубляется различиями в механизмах обмена. При использовании стандартной обработки «Универсальный обмен данными XML» выгрузка может происходить построчно в виде отдельных менеджеров записей (РегистрСведенийМенеджерЗаписи). Но при переходе на регулярную синхронизацию данных (через планы обмена и БСП) платформа начинает оперировать наборами записей (РегистрСведенийНаборЗаписей), что мгновенно вскрывает архитектурные пробелы в правилах конвертации.

Причина №2: Конфликт имен и специфика COM-соединения

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


Если Не ЗначениеЗаполнено(Объект.Объект) Или Не ЗначениеЗаполнено(Объект.Тип) Тогда
    Отказ = Истина;
КонецЕсли;

Этот код отлично работает при файловом обмене через XML, но при переходе на COM-соединение начинает вызывать критическую ошибку выполнения: «Не обнаружен объект Объект» или «Поле объекта не обнаружено». Почему это происходит?

Пошаговое руководство по исправлению проблемы в КД 2.1

Чтобы полностью исключить затирание регистра КонтактнаяИнформация и обеспечить корректную работу правил как через XML, так и через COM, мы должны реализовать комплексную защиту на трех уровнях обмена.

Шаг 1. Жесткая фильтрация на стороне источника (Перед выгрузкой)

Самый надежный способ избежать записи «битых» или пустых наборов в приемнике — вообще не выгружать их из базы-источника. Забудьте про медленные и потенциально опасные проверки через строковые функции вроде Найти(Строка(Источник.Объект), "Объект не найден"). Проверяйте объекты базы напрямую.

Откройте ПКО регистра КонтактнаяИнформация, перейдите в обработчик события «Перед выгрузкой» (или «Перед выгрузкой объекта») и добавьте следующий код:


// Проверяем заполненность ключевых полей источника
Если Не ЗначениеЗаполнено(Источник.Объект) 
   Или Не ЗначениеЗаполнено(Источник.Тип) 
   Или Не ЗначениеЗаполнено(Источник.Вид) Тогда
    
    Отказ = Истина;
    Возврат;
КонецЕсли;

// Проверяем на наличие "битых" ссылок (объектов, удаленных из базы)
Попытка
    Если Источник.Объект.ПолучитьОбъект() = Неопределено Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
Исключение
    // На случай, если тип измерения "Объект" не имеет метода ПолучитьОбъект()
    Если Источник.Объект.Пустая() Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
КонецПопытки;

Шаг 2. Обязательная настройка ПКС и Полей поиска

Убедитесь, что в ПКО регистра сведений созданы правила конвертации свойств (ПКС) для всех ключевых измерений: Объект, Тип и Вид. Если эти правила отсутствуют, приемник не сможет правильно сопоставить пришедшие записи и гарантированно запишет пустой набор.

Выполните следующие настройки в Конвертации данных:

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

Шаг 3. Безопасный и универсальный обработчик в приемнике (При загрузке)

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

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


// Определяем тип загружаемого объекта
ТипЗагружаемогоОбъекта = ТипЗнч(Объект);

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

ИначеЕсли ТипЗагружаемогоОбъекта = Тип("РегистрСведенийМенеджерЗаписи.КонтактнаяИнформация") Тогда
    
    // Если это менеджер записи, безопасно проверяем свойства через метаданные или явное обращение
    Попытка
        Если Не ЗначениеЗаполнено(Объект.Объект) 
           Или Не ЗначениеЗаполнено(Объект.Тип) 
           Или Не ЗначениеЗаполнено(Объект.Вид) Тогда
            Отказ = Истина;
        КонецЕсли;
    Исключение
        // Резервный вариант на случай сложных конфликтов имен в COM-соединении
        Отказ = Истина;
    КонецПопытки;

КонецЕсли;

Этот код надежно защитит базу от непреднамеренной очистки данных. Даже если на стороне источника по какой-то причине сформируется некорректная выгрузка, база-приемник отклонит пустой набор записей благодаря флагу Отказ = Истина, сохранив все накопленные контактные данные ваших клиентов и контрагентов в целости.

← На главную