При разработке обработок регистрации в 1С часто возникает задача одновременного создания нескольких связанных объектов. Типичный пример: создание Контрагента и связанного с ним Пользователя. Основная сложность для начинающих разработчиков заключается в правильной передаче ссылки одного объекта в реквизит другого. Рассмотрим подробно, как это реализовать и какие нюансы платформы 1С:Предприятие 8 необходимо учитывать.
Проанализируем ситуацию, когда разработчик пытается присвоить реквизиту с типом СправочникСсылка.Контрагенты текстовое значение, например, Наименование. В 1С это приводит к тому, что система пытается выполнить неявное преобразование. Поскольку строка с ФИО не является уникальным идентификатором ссылки, в реквизит записывается ПустаяСсылка. Выясним причину: реквизит справочника ожидает объект типа «Ссылка», а не просто текст.
Для корректного заполнения нам необходимо сначала физически записать объект в базу данных, чтобы система присвоила ему уникальный идентификатор (GUID), и только после этого использовать полученную ссылку. Рассмотрим по шагам, как правильно выстроить алгоритм создания объектов.
Чтобы заполнить реквизит Клиент в справочнике Пользователи, нам уже нужно иметь созданного клиента. Следовательно, в коде создание Контрагента должно стоять выше создания Пользователя. Разберем пример кода, реализующий эту логику:
// Сначала создаем и записываем Контрагента
НовыйКлиент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКлиент.Наименование = Объект.ФИО;
НовыйКлиент.Телефон = Объект.Телефон;
// Обязательно записываем, чтобы получить ссылку
НовыйКлиент.Записать();
// Теперь создаем Пользователя
НовыйПользователь = Справочники.Пользователи.СоздатьЭлемент();
НовыйПользователь.Наименование = Объект.ФИО;
// Присваиваем именно ССЫЛКУ на только что созданного контрагента
НовыйПользователь.Клиент = НовыйКлиент.Ссылка;
НовыйПользователь.Записать();
В этом примере мы используем свойство Ссылка объекта НовыйКлиент. Важно помнить, что до вызова метода Записать() ссылка у нового объекта может быть пустой (если не использован метод УстановитьСсылкуНового()), поэтому порядок вызовов критичен.
Важно понимать, что работа с объектами (метод СоздатьЭлемент) в управляемом приложении возможна только в контексте &НаСервере. Если вы пишете код в модуле формы обработки, процедура должна выглядеть следующим образом:
&НаКлиенте
Процедура Зарегистрировать(Команда)
ЗарегистрироватьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ЗарегистрироватьНаСервере()
// Логика создания объектов, описанная выше
КонецПроцедуры
Проанализируем ситуацию: что произойдет, если Контрагент создастся успешно, а при записи Пользователя возникнет ошибка (например, из-за нарушения уникальности логина)? В базе останется «сиротская» запись контрагента. Чтобы этого избежать, мы рекомендуем использовать транзакции. Рассмотрим подробнее реализацию:
НачатьТранзакцию();
Попытка
// Создание контрагента
НовыйКлиент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКлиент.Наименование = ФИО;
НовыйКлиент.Записать();
// Создание пользователя
НовыйПользователь = Справочники.Пользователи.СоздатьЭлемент();
НовыйПользователь.Наименование = ФИО;
НовыйПользователь.Клиент = НовыйКлиент.Ссылка;
НовыйПользователь.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка при регистрации: " + ОписаниеОшибки());
КонецПопытки;
Чтобы не плодить одинаковые записи при каждом нажатии кнопки, перед созданием следует выполнить поиск. Посмотрим на пример использования метода НайтиПоНаименованию:
СсылкаНаКлиента = Справочники.Контрагенты.НайтиПоНаименованию(ФИО);
Если СсылкаНаКлиента.Пустая() Тогда
// Если не найден, создаем нового
НовыйКлиент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКлиент.Наименование = ФИО;
НовыйКлиент.Записать();
СсылкаНаКлиента = НовыйКлиент.Ссылка;
КонецЕсли;
// Теперь используем СсылкаНаКлиента для заполнения реквизита Пользователя
Для оптимизации кода и повышения его надежности следует придерживаться следующих правил:
ЗаполнитьЗначенияСвойств: Если реквизиты обработки называются так же, как в справочнике, используйте ЗаполнитьЗначенияСвойств(НовыйКлиент, Объект);. Это сократит количество строк кода.ОбменДанными.Загрузка = Истина; перед записью объекта. Это отключит лишние проверки в модуле объекта и ускорит работу.Таким образом, мы выяснили, что для решения задачи необходимо соблюдать строгую типизацию данных (передавать ссылку, а не строку) и придерживаться правильной последовательности действий: Создание -> Запись -> Получение ссылки -> Использование ссылки в другом объекте.