В практике разработчика 1С нередко возникают задачи по оптимизации переноса данных между информационными базами. Одной из таких стратегий является перенос движений регистров (бухгалтерии, накопления или сведений) без переноса самих объектов ссылочного типа (справочников, документов). В этом случае в базе-приемнике образуются так называемые «битые» ссылки — значения, которые имеют тип и уникальный идентификатор (GUID), но физически отсутствуют в таблицах базы данных. Рассмотрим подробно, как реализовать такую запись и как бороться с возникающими при этом платформенными ошибками.
С точки зрения платформы 1С, «битая» ссылка — это объект ссылочного типа, для которого в базе данных нет соответствующей записи. Программно такую ссылку можно получить, зная её УникальныйИдентификатор. Проанализируем пример создания подобной ссылки:
// Создание ссылки на несуществующий элемент справочника
Идентификатор = Новый УникальныйИдентификатор("d1c2b3a4-e5f6-7890-1234-567890abcdef");
Ссылка = Справочники.Контрагенты.ПолучитьСсылку(Идентификатор);
Платформа позволяет записывать такие ссылки в поля регистров. При просмотре через консоль запросов или в интерфейсе мы увидим надпись «Объект не найден». Это штатная ситуация, которая не должна приводить к краху системы, если соблюдены правила типизации данных.
При попытке записать набор записей регистра бухгалтерии (или любого другого регистра) программисты часто сталкиваются с исключением: Ошибка при вызове метода контекста (Записать): Запись не верна!. Выясним основные причины этой ошибки, когда мы работаем с внешними данными:
Период, Регистратор или в измерениях, для которых запрещены пустые значения.СправочникСсылка.Склады в поле, предназначенное для СправочникСсылка.Организации.Субконто.Первое, что мы должны сделать при программной загрузке данных — это установить свойство ОбменДанными.Загрузка в значение Истина. Рассмотрим, как это влияет на процесс записи:
Этот флаг отключает большинство прикладных проверок, реализованных в модулях набора записей (процедуры ПередЗаписью, ПриЗаписи), а также некоторые платформенные проверки бизнес-логики. Однако, важно понимать: этот флаг не отключает проверку типов данных и проверку существования метаданных.
Пример корректного кода загрузки из XML, который мы можем использовать:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
ЧтениеXML.Прочитать(); // Чтение корня
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
// Десериализация набора записей или объекта
НаборЗаписей = ПрочитатьXML(ЧтениеXML);
Попытка
// Включаем режим загрузки для обхода проверок
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();
Исключение
Сообщить("Ошибка записи: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
ЧтениеXML.Закрыть();
Как проанализировано в рассматриваемой теме, наиболее коварная причина ошибки «Запись не верна» при переносе движений бухгалтерии кроется в несоответствии идентификаторов элементов ПВХ (Видов субконто). Проанализируем ситуацию:
В регистре бухгалтерии значение субконто привязано к конкретному ВидуСубконто. Сам ВидСубконто является ссылкой на элемент Плана видов характеристик. Если в базе-источнике элемент «Контрагенты» имеет один GUID, а в базе-приемнике — другой, то при загрузке платформа не сможет сопоставить значение. Даже если мы записываем «битую» ссылку, система должна понимать, к какому типу данных она относится. Если ссылка на ВидСубконто не найдена в ПВХ приемника, система не может определить правила типизации для этого поля, что и вызывает ошибку Запись не верна!.
Решение проблемы: Перед переносом движений необходимо убедиться, что все элементы Планов видов характеристик, используемые в качестве видов субконто, имеют идентичные GUID в обеих базах. Если они создавались вручную в разных базах, их необходимо синхронизировать программно.
Рассмотрим метод, который позволяет имитировать наличие «битой» ссылки в регистре для отладки механизмов загрузки. Нам не нужно создавать и удалять объект, достаточно использовать метод УстановитьСсылкуНового() в связке с записью в регистр:
// 1. Генерируем новый GUID, которого точно нет в базе
НовыйGUID = Новый УникальныйИдентификатор();
НужнаяСсылка = Справочники.Номенклатура.ПолучитьСсылку(НовыйGUID);
// 2. Создаем запись в регистре с этой ссылкой
Набор = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(ТекущаяДата());
Запись = Набор.Добавить();
Запись.Период = ТекущаяДата();
Запись.Номенклатура = НужнаяСсылка; // Вот она, битая ссылка
Запись.Цена = 100;
Попытка
Набор.Записать();
Сообщить("Запись успешно создана с битой ссылкой");
Исключение
Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;
Если вы столкнулись с этой проблемой при загрузке данных, выполните следующие шаги:
Период и Регистратор. Если регистратор сам является «битой» ссылкой, проверьте, разрешен ли этот тип документа в качестве регистратора для данного регистра в метаданных.ВидСубконто.УникальныйИдентификатор() в обеих базах для сравнения.Записать(). Особое внимание уделите полям, где отображается "<Объект не найден>...". Если вместо этого вы видите Неопределено там, где должна быть ссылка — это и есть причина ошибки.ОбменДанными.Загрузка = Истина устанавливается именно для того объекта, который вы записываете (набора записей).Проанализировав ситуацию, мы видим, что платформа 1С достаточно лояльна к «битым» ссылкам, но крайне требовательна к структуре метаданных. Пока типы данных и ссылки на метаданные (такие как виды субконто) консистентны, система позволит хранить записи, ссылающиеся в «никуда».