В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью автоматизировать заполнение дополнительных сведений. Типичная ситуация: при заполнении табличной части документа из внешней обработки необходимо одновременно установить значение некоего коэффициента или признака, который хранится не в самом документе, а в регистре сведений ДополнительныеСведения. Однако, если в конфигурации включено версионирование объектов, простая запись в регистр может привести к критической ошибке. В этой статье мы подробно разберем, почему возникает ошибка «Элемент не выбран!» и как правильно использовать механизмы Библиотеки стандартных подсистем (БСП) для решения этой задачи.
Рассмотрим ситуацию, описанную в теме. При попытке записи набора записей или менеджера записи в регистр ДополнительныеСведения, система выдает ошибку в общем модуле ВерсионированиеОбъектов. Текст ошибки выглядит следующим образом:
{ОбщийМодуль.ВерсионированиеОбъектов.Модуль(267)}: Ошибка при вызове метода контекста (ПолучитьОбъект) Источник = Источник.ПолучитьОбъект(); по причине: Элемент не выбран!
Давайте выясним причину этого поведения. В БСП настроены подписки на события, которые отслеживают изменения в регистре дополнительных сведений. Когда мы записываем сведения для конкретного документа, срабатывает механизм версионирования, который пытается создать новую версию основного объекта (в нашем случае — документа). Для этого подсистема должна получить объект документа по ссылке.
Если код выполняется в обработке заполнения для нового документа, который еще не был физически записан в базу данных, ссылка на него уже существует (сформирована платформой), но в самой базе данных объекта еще нет. Метод ПолучитьОбъект(), вызванный от такой «пустой» ссылки в модуле версионирования, закономерно выдает исключение «Элемент не выбран».
Вместо того чтобы вручную создавать менеджер записи и заполнять измерения регистра, рекомендуется использовать программный интерфейс БСП. Это наиболее правильный и безопасный путь, так как стандартные процедуры общего модуля уже содержат необходимые проверки и корректно взаимодействуют с другими подсистемами (версионирование, даты запрета изменения, права доступа).
Проанализируем работу с общим модулем УправлениеСвойствами. Для записи дополнительных сведений предназначена процедура ЗаписатьДополнительныеСведения. Рассмотрим пример кода:
// СсылкаНаОбъект - ссылка на документ, для которого пишем сведения
// ИмяСвойства - наименование или ссылка на ПВХ ДополнительныеРеквизитыИСведения
// ЗначениеСвойства - записываемое значение
СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Коэффициент Пересчета");
Если Не СвойствоСсылка.Пустая() Тогда
// Подготовим структуру со сведениями
ТаблицаСведений = Новый ТаблицаЗначений;
ТаблицаСведений.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
ТаблицаСведений.Колонки.Добавить("Значение");
НоваяСтрока = ТаблицаСведений.Добавить();
НоваяСтрока.Свойство = СвойствоСсылка;
НоваяСтрока.Значение = Объект.Коэффициент;
// Вызов стандартного метода БСП
УправлениеСвойствами.ЗаписатьДополнительныеСведения(СсылкаНаОбъект, ТаблицаСведений);
КонецЕсли;
Этот метод самостоятельно управляет транзакцией и гарантирует, что данные будут записаны корректно. Однако помните: дополнительные сведения нельзя записать для объекта, который не записан в базу. Если вы работаете в форме нового документа, сначала необходимо выполнить Объект.Записать().
Если по каким-то причинам вы предпочитаете использовать прямой метод записи в регистр (например, в старых версиях конфигураций или при специфических требованиях), необходимо добавить проверку состояния объекта. Разберем по шагам, как модифицировать исходный код из сообщения автора:
Процедура ЗапишемКоэффициент(СсылкаНаДок)
// 1. Проверяем, что ссылка не пустая и объект существует в базе
Если СсылкаНаДок.Пустая() Или СсылкаНаДок.ПолучитьОбъект() = Неопределено Тогда
Возврат; // Нельзя писать сведения для несуществующего документа
КонецЕсли;
НашКоэф = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Коэффициент Пересчета");
Если Не НашКоэф.Пустая() Тогда
МЗ = РегистрыСведений.ДополнительныеСведения.СоздатьМенеджерЗаписи();
МЗ.Объект = СсылкаНаДок;
МЗ.Свойство = НашКоэф;
// Читаем существующую запись, чтобы не перезаписывать лишний раз
МЗ.Прочитать();
МЗ.Значение = Объект.Коэффициент;
Попытка
МЗ.Записать(Истина);
Исключение
ЗаписьЖурналаРегистрации("ЗаписьСведений", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Важный момент: Использование параметра Истина в методе Записать() означает замещение существующей записи. Это критично для корректной работы регистра сведений с уникальным ключом «Объект + Свойство».
Проанализируем ситуацию: возможно, для вашей задачи лучше подходят Дополнительные реквизиты, а не сведения. Давайте выясним принципиальную разницу:
ДополнительныеРеквизиты). Они записываются одновременно с документом в одной транзакции. Если вы программно заполните эту табличную часть в обработке заполнения, то при нажатии кнопки «Записать» в документе всё сохранится автоматически без лишних вызовов регистров и ошибок версионирования.ДополнительныеСведения. Они существуют «отдельно» от документа. Их удобно использовать, когда нужно добавить информацию к закрытым периодам или когда нельзя менять сам документ.Если вы автоматизируете заполнение данных при создании документа, настоятельно рекомендуем использовать дополнительные реквизиты. Это избавит вас от проблем с транзакциями и версионированием.
Иногда программная запись сведений вызывает создание «мусорных» версий в истории изменений документа, что затрудняет анализ действий пользователя. Чтобы этого избежать при использовании БСП, можно воспользоваться дополнительными параметрами записи.
В некоторых случаях программисты временно отключают версионирование для текущего сеанса или используют свойство ДополнительныеСвойства у объекта документа, передавая туда флаг ОтказОтВерсионирования (точное имя свойства зависит от версии БСП и настроек подписки). Однако при использовании УправлениеСвойствами.ЗаписатьДополнительныеСведения система ведет себя максимально сбалансированно.
Подведем итоги нашего разбора:
Ссылка.Пустая() перед работой с регистром.УправлениеСвойствами.Объект.Записать()), и только потом вызывайте процедуру установки сведений.Соблюдение этих правил позволит вам создавать надежные механизмы заполнения данных, которые не будут конфликтовать со стандартными подсистемами конфигураций на базе 1С:ERP, УТ 11 или Бухгалтерии предприятия.