При реализации механизмов обмена данными между различными базами 1С программисты часто сталкиваются с ситуацией, когда объекты, которые должны сопоставляться по уникальному идентификатору (ГУИД), начинают дублироваться. Особенно часто эта проблема проявляется в сложных справочниках, таких как Сотрудники. Проанализируем типичную ситуацию: при первой загрузке элемент создается корректно, но при повторной — система «не видит» существующий объект и создает новый, даже если код поиска кажется безупречным. Разберем по шагам, почему это происходит и как правильно организовать поиск и запись объектов с сохранением их исходных идентификаторов.
Рассмотрим ситуацию, с которой столкнулся автор темы. В коде выполняется попытка получить ссылку из строки ГУИД, а затем проверить наличие объекта в базе данных. Если объект не найден, создается новый с принудительной установкой ссылки. Однако при следующей итерации поиска по тому же самому ГУИД система снова сообщает, что «объект не найден».
Типичный код, который ведет к такой ошибке, выглядит следующим образом:
СотрудникСсылка = Справочники.Сотрудники.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаТЗ.ГУИДСотрудник));
Если СотрудникСсылка.ПолучитьОбъект() = Неопределено Тогда
СотрудникОбъект = Справочники.Сотрудники.СоздатьЭлемент();
СотрудникОбъект.УстановитьСсылкуНового(СотрудникСсылка);
Иначе
СотрудникОбъект = СотрудникСсылка.ПолучитьОбъект();
КонецЕсли;
Проанализируем этот фрагмент. Главная методическая ошибка здесь заключается в проверке существования объекта. Метод ПолучитьСсылку() платформы 1С всегда возвращает ссылку, даже если объекта с таким идентификатором еще нет в базе данных. Такая ссылка называется «битой» или «пустышкой». Проверка СотрудникСсылка.Пустая() для ссылки, созданной из конкретного ГУИД, всегда будет возвращать Ложь, так как ссылка содержит данные (сам идентификатор), хотя записи в таблице базы данных еще не существует.
Использование метода ПолучитьОбъект() для проверки существования записи — крайне неэффективная операция. Платформа пытается считать все данные объекта из базы данных в память сервера. Если объектов много, это приведет к значительным задержкам и избыточной нагрузке на СУБД.
Наиболее правильным и быстрым способом проверки является использование запроса. Запрос обращается напрямую к таблицам базы данных, минуя кэш объектов, и возвращает результат максимально оперативно. Рассмотрим, как переписать проверку правильно:
// Получаем ссылку из строки
СотрудникСсылка = Справочники.Сотрудники.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаТЗ.ГУИДСотрудник));
// Проверяем наличие записи в базе данных через запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Сотрудники.Ссылка КАК Ссылка
|ИЗ
| Справочник.Сотрудники КАК Сотрудники
|ГДЕ
| Сотрудники.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СотрудникСсылка);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
// Объекта нет, будем создавать новый
СотрудникОбъект = Справочники.Сотрудники.СоздатьЭлемент();
СотрудникОбъект.УстановитьСсылкуНового(СотрудникСсылка);
Иначе
// Объект найден, получаем его для редактирования
СотрудникОбъект = СотрудникСсылка.ПолучитьОбъект();
КонецЕсли;
Даже если мы исправим код проверки на запрос, проблема может сохраниться: при записи нового объекта 1С может проигнорировать УстановитьСсылкуНового() и сгенерировать свой собственный ГУИД. Почему это происходит со справочником Сотрудники, но работает с ФизическиеЛица?
Выясним причину. В современных конфигурациях (ЗУП 3.1, ERP, КА) справочник Сотрудники — это не просто список имен, а сложный узел бизнес-логики. При записи элемента срабатывает множество подписок на события и обработчиков в модуле объекта. В этих обработчиках может выполняться логика, которая косвенно вызывает перезапись или переопределение ссылки, особенно если конфигурация настроена на строгий контроль уникальности или автоматическую генерацию связей с физическими лицами.
Ключевое решение: Чтобы платформа гарантированно применила вашу ссылку и не запускала лишние проверки, которые могут «сбить» установленный ГУИД, необходимо использовать свойство ОбменДанными.Загрузка.
Когда свойство ОбменДанными.Загрузка установлено в значение Истина:
УстановитьСсылкуНового() отрабатывает корректно и сохраняется в БД.С учетом всех выявленных нюансов, правильный код для загрузки сотрудников с сохранением ГУИД из другой базы будет выглядеть так:
// 1. Подготовка идентификатора
Идентификатор = Новый УникальныйИдентификатор(СтрокаТЗ.ГУИДСотрудник);
СотрудникСсылка = Справочники.Сотрудники.ПолучитьСсылку(Идентификатор);
// 2. Поиск существующего элемента через легкий запрос
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Сотрудники ГДЕ Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", СотрудникСсылка);
Если Запрос.Выполнить().Пустой() Тогда
// Создаем новый элемент
СотрудникОбъект = Справочники.Сотрудники.СоздатьЭлемент();
// Важно: устанавливаем ссылку до первой записи!
СотрудникОбъект.УстановитьСсылкуНового(СотрудникСсылка);
Иначе
// Редактируем существующий
СотрудникОбъект = СотрудникСсылка.ПолучитьОбъект();
КонецЕсли;
// 3. Установка режима загрузки - ЭТО КРИТИЧЕСКИ ВАЖНО
СотрудникОбъект.ОбменДанными.Загрузка = Истина;
// 4. Заполнение реквизитов
СотрудникОбъект.Наименование = СтрокаТЗ.НаименованиеСотрудник;
СотрудникОбъект.ФизическоеЛицо = ФизЛицоСсылка; // Предварительно найденное ФЛ
СотрудникОбъект.Организация = ОрганизацияСсылка;
// 5. Запись
Попытка
СотрудникОбъект.Записать();
Сообщить("Сотрудник успешно обработан: " + СотрудникОбъект.Наименование);
Исключение
Сообщить("Ошибка при записи сотрудника: " + ОписаниеОшибки());
КонецПопытки;
Разберем еще несколько важных моментов, которые помогут сделать ваш обмен данными более надежным и производительным.
Использование XMLЗначение
Для получения ссылки из строки ГУИД вместо конструкции ПолучитьСсылку(Новый УникальныйИдентификатор(...)) можно использовать XMLЗначение. Этот метод работает быстрее, так как платформа оптимизирует создание объекта идентификатора внутри себя. Пример:
СотрудникСсылка = XMLЗначение(Тип("СправочникСсылка.Сотрудники"), СтрокаТЗ.ГУИДСотрудник);
Проблема кэширования
В редких случаях, если вы записываете объект и тут же пытаетесь его найти, объект может не «проявиться» в результатах запроса из-за особенностей работы индексов СУБД или кэширования на сервере 1С. Однако использование ОбменДанными.Загрузка = Истина сводит риск возникновения таких коллизий к минимуму, так как запись происходит максимально «прозрачно» для системы.
Связи между справочниками
Помните, что справочник Сотрудники жестко связан со справочником ФизическиеЛица. Если вы переносите сотрудников из другой базы, убедитесь, что вы сначала создали (или нашли по ГУИД) соответствующее ФизическоеЛицо и присвоили его реквизиту СотрудникОбъект.ФизическоеЛицо. Если этого не сделать, автоматические механизмы конфигурации (даже в режиме загрузки) могут создать пустые или некорректные записи в сопутствующих регистрах сведений.
Проанализировав ситуацию, мы видим, что «необъяснимое» поведение программы всегда имеет под собой техническую основу. Использование режима загрузки — это стандарт де-факто для любых операций импорта данных, где требуется сохранить ссылочную целостность между различными информационными системами.