Как предотвратить задвоение предопределенных элементов при обмене через XML в 1С?

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

При организации обмена между независимыми базами данных 1С (например, между центральной базой и мобильным приложением или филиалом) разработчики нередко сталкиваются с неприятным эффектом: после первой же выгрузки и загрузки через ЧтениеXML и ЗаписьXML предопределенные элементы справочников удваиваются. В интерфейсе появляются две одинаковые записи, причем у обеих отображается пиктограмма предопределенного элемента с кружком. Разберем механизм возникновения этой ошибки и изучим эффективные способы её решения.

Выясним причину задвоения предопределенных данных

Проанализируем, как платформа 1С работает с предопределенными объектами. Начиная с версии платформы 8.3 (при отключенном режиме совместимости с версией 8.2), предопределенные элементы перестали жестко привязываться к фиксированным внутренним идентификаторам на уровне конфигурации. Теперь связь строки таблицы с описанием в метаданных осуществляется по специальному строковому реквизиту ИмяПредопределенныхДанных, тогда как ссылочный уникальный идентификатор (GUID) генерируется динамически при создании элемента в информационной базе.

Если базы инициализируются независимо (то есть мобильная база создавалась не как начальный образ РИБ), то при первом запуске платформа автоматически генерирует предопределенные элементы в каждой базе со своими собственными, не совпадающими GUID.

Когда мы выгружаем данные из источника и читаем XML в приемнике, платформа осуществляет поиск существующего объекта по переданному GUID ссылки. Не находя в приемнике элемент с таким GUID, система создает новый объект. Поскольку обмен данными обычно выполняется с установленным свойством ОбменДанными.Загрузка = Истина, платформенные проверки отключаются, в том числе временно игнорируется уникальность поля ИмяПредопределенныхДанных. В итоге мы получаем два элемента с одинаковым именем предопределенного узла, а ошибка контроля уникальности проявится позже — когда пользователь или регламентное задание попытается штатно записать такой элемент.

Способ 1. Отключение автоматического обновления предопределенных данных в конфигураторе

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

  1. Откроем конфигуратор базы-приемника (или мобильного приложения).
  2. Найдем проблемный справочник и откроем его палитру свойств.
  3. Найдем свойство Обновление предопределенных данных (по умолчанию установлено значение Авто).
  4. Установим значение в Не обновлять автоматически.
  5. Применим изменения в информационной базе.

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

Способ 2. Программное отключение инициализации перед обменом

Если мы разрабатываем универсальное решение и не хотим менять свойства объектов в конфигураторе вручную, разберем программный вариант управления этим механизмом. Платформа 1С позволяет управлять созданием предопределенных записей непосредственно из встроенного языка.

Мы можем отключить автоматическое создание элементов как для конкретного справочника, так и для всей информационной базы в целом:


// Отключение автосоздания для одного конкретного справочника
Справочники.Номенклатура.УстановитьОбновлениеПредопределенныхДанных(
    ОбновлениеПредопределенныхДанных.НеОбновлятьАвтоматически
);

// Или полное отключение создания предопределенных данных во всей базе
УстановитьОбновлениеПредопределенныхДанныхИнформационнойБазы(
    ОбновлениеПредопределенныхДанных.НеОбновлятьАвтоматически
);

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

Способ 3. Сопоставление по имени предопределенных данных при чтении XML

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

  1. При чтении узла объекта определяем, передано ли значение для ИмяПредопределенныхДанных.
  2. Если объект является предопределенным, выполняем поиск в базе-приемнике не по ссылке, а по имени предопределенного элемента. Для этого используем менеджер справочника Справочники[ИмяСправочника][ИмяПредопределенного] либо запрос к таблице.
  3. При обнаружении существующего локального элемента мы не создаем новый объект, а заполняем реквизиты найденного элемента данными из XML и сохраняем его.

Как исправить уже возникшие дубли

Разберем ситуацию, когда обмен уже прошел и задвоенные элементы появились в базе. Интерактивно удалить или объединить их платформа не позволит, так как обе записи имеют признак предопределенности. Проанализируем, как устранить дубли программно.

Для исправления необходимо снять признак предопределенности с дублирующего элемента, перенести ссылки и затем удалить его:


// Получаем объект лишнего (дублирующего) предопределенного элемента
ДубльОбъект = ДубльСсылка.ПолучитьОбъект();

// Принудительно очищаем имя предопределенных данных
ДубльОбъект.ИмяПредопределенныхДанных = "";

// Запись выполняем в режиме загрузки данных, чтобы отключить проверки
ДубльОбъект.ОбменДанными.Загрузка = Истина;
ДубльОбъект.Записать();

// После этого элемент теряет пиктограмму предопределенного и становится обычным объектом
// Теперь можно заменить ссылки на правильный элемент и удалить дубль

После снятия признака предопределенности с дубликата воспользуемся стандартным методом НайтиПоСсылкам() или типовыми механизмами замены дублей, чтобы перенаправить все движения и документы на корректный элемент, после чего удалим ненужную запись штатным удалением помеченных объектов.

← На главную