При организации обмена между независимыми базами данных 1С (например, между центральной базой и мобильным приложением или филиалом) разработчики нередко сталкиваются с неприятным эффектом: после первой же выгрузки и загрузки через ЧтениеXML и ЗаписьXML предопределенные элементы справочников удваиваются. В интерфейсе появляются две одинаковые записи, причем у обеих отображается пиктограмма предопределенного элемента с кружком. Разберем механизм возникновения этой ошибки и изучим эффективные способы её решения.
Проанализируем, как платформа 1С работает с предопределенными объектами. Начиная с версии платформы 8.3 (при отключенном режиме совместимости с версией 8.2), предопределенные элементы перестали жестко привязываться к фиксированным внутренним идентификаторам на уровне конфигурации. Теперь связь строки таблицы с описанием в метаданных осуществляется по специальному строковому реквизиту ИмяПредопределенныхДанных, тогда как ссылочный уникальный идентификатор (GUID) генерируется динамически при создании элемента в информационной базе.
Если базы инициализируются независимо (то есть мобильная база создавалась не как начальный образ РИБ), то при первом запуске платформа автоматически генерирует предопределенные элементы в каждой базе со своими собственными, не совпадающими GUID.
Когда мы выгружаем данные из источника и читаем XML в приемнике, платформа осуществляет поиск существующего объекта по переданному GUID ссылки. Не находя в приемнике элемент с таким GUID, система создает новый объект. Поскольку обмен данными обычно выполняется с установленным свойством ОбменДанными.Загрузка = Истина, платформенные проверки отключаются, в том числе временно игнорируется уникальность поля ИмяПредопределенныхДанных. В итоге мы получаем два элемента с одинаковым именем предопределенного узла, а ошибка контроля уникальности проявится позже — когда пользователь или регламентное задание попытается штатно записать такой элемент.
Рассмотрим штатный и наиболее надежный способ предотвращения коллизии, если мы можем вносить изменения в структуру базы-приемника. В дереве метаданных конфигурации предусмотрено специальное свойство, управляющее поведением предопределенных записей.
Авто).Посмотрим на результат: теперь платформа не будет создавать предопределенные элементы при обновлении конфигурации или первом обращении к таблице. Справочник останется пустым до тех пор, пока не выполнится первая загрузка XML из центральной базы. В процессе загрузки элементы создадутся с GUID базы-источника, сохранив при этом признак предопределенности, и в дальнейшем будут безошибочно сопоставляться.
Если мы разрабатываем универсальное решение и не хотим менять свойства объектов в конфигураторе вручную, разберем программный вариант управления этим механизмом. Платформа 1С позволяет управлять созданием предопределенных записей непосредственно из встроенного языка.
Мы можем отключить автоматическое создание элементов как для конкретного справочника, так и для всей информационной базы в целом:
// Отключение автосоздания для одного конкретного справочника
Справочники.Номенклатура.УстановитьОбновлениеПредопределенныхДанных(
ОбновлениеПредопределенныхДанных.НеОбновлятьАвтоматически
);
// Или полное отключение создания предопределенных данных во всей базе
УстановитьОбновлениеПредопределенныхДанныхИнформационнойБазы(
ОбновлениеПредопределенныхДанных.НеОбновлятьАвтоматически
);
Выполнив этот код до первого наполнения базы или до первого обращения к таблицам, мы гарантируем, что платформа не сгенерирует лишние локальные идентификаторы.
Если базы уже содержат данные и отключить автосоздание невозможно, проанализируем алгоритм ручной десериализации. Стандартный метод ПрочитатьXML() выполняет прямое сопоставление по входящему GUID. Чтобы избежать создания дублей, модифицируем логику чтения данных:
ИмяПредопределенныхДанных.Справочники[ИмяСправочника][ИмяПредопределенного] либо запрос к таблице.Разберем ситуацию, когда обмен уже прошел и задвоенные элементы появились в базе. Интерактивно удалить или объединить их платформа не позволит, так как обе записи имеют признак предопределенности. Проанализируем, как устранить дубли программно.
Для исправления необходимо снять признак предопределенности с дублирующего элемента, перенести ссылки и затем удалить его:
// Получаем объект лишнего (дублирующего) предопределенного элемента
ДубльОбъект = ДубльСсылка.ПолучитьОбъект();
// Принудительно очищаем имя предопределенных данных
ДубльОбъект.ИмяПредопределенныхДанных = "";
// Запись выполняем в режиме загрузки данных, чтобы отключить проверки
ДубльОбъект.ОбменДанными.Загрузка = Истина;
ДубльОбъект.Записать();
// После этого элемент теряет пиктограмму предопределенного и становится обычным объектом
// Теперь можно заменить ссылки на правильный элемент и удалить дубль
После снятия признака предопределенности с дубликата воспользуемся стандартным методом НайтиПоСсылкам() или типовыми механизмами замены дублей, чтобы перенаправить все движения и документы на корректный элемент, после чего удалим ненужную запись штатным удалением помеченных объектов.