При разработке обработок и отчетов в конфигурациях 1С (таких как Управление торговлей 10.3, УПП 1.3 или комплексных системах) часто возникает задача чтения и программной установки дополнительных свойств объектов. Начинающие разработчики нередко сталкиваются с ситуацией, когда запрос к регистру сведений ЗначенияСвойствОбъектов не возвращает данных, хотя в базе они присутствуют.
Разберем по шагам, почему возникают подобные ошибки, как правильно передавать параметры в запрос и как корректно выполнять запись новых значений свойств.
Проанализируем исходный код функции получения значения свойства:
Функция ПолучитьЗначениеСвойства(Объект, Свойство)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Значение КАК ЗначениеСвойства
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Объект = &Объект
| И ЗначенияСвойствОбъектов.Свойство = &Свойство";
Запрос.УстановитьПараметр("Объект", Объект);
Запрос.УстановитьПараметр("Свойство", Свойство);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.ЗначениеСвойства;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Если вызвать данную функцию, передав в качестве параметра строку вида "Статус":
ТекущийСтатус = ПолучитьЗначениеСвойства(Выборка.Номенклатура, "Статус");
Запрос вернет пустой результат. Выясним причину: измерение Свойство регистра сведений ЗначенияСвойствОбъектов имеет ссылочный тип ПланВидовХарактеристикСсылка.СвойстваОбъектов (или ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения в конфигурациях на базе БСП), а не тип Строка.
Чтобы запрос отработал корректно, необходимо передавать ссылку на элемент плана видов характеристик:
СвойствоСсылка = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Статус", Истина);
ТекущийСтатус = ПолучитьЗначениеСвойства(Выборка.Номенклатура, СвойствоСсылка);
Вторая частая ошибка — передача в параметр &Объект строкового наименования или другого неподходящего типа вместо ссылки на справочник Справочники.Номенклатура.
Измерение Объект в регистре сведений типизировано ссылками на объекты метаданных. Если в выборке или таблице содержится строка, перед передачей параметра необходимо получить ссылку:
СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоНаименованию(Выборка.Номенклатура, Истина);
ТекущийСтатус = ПолучитьЗначениеСвойства(СсылкаНоменклатура, СвойствоСсылка);
Вызов отдельной функции с запросом внутри цикла обхода строк — критическая ошибка производительности. При обработке большого количества строк номенклатуры обращение к базе данных в цикле существенно замедляет работу системы.
Рассмотрим, как объединить получение данных и свойств в один запрос с помощью ЛЕВОЕ СОЕДИНЕНИЕ:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура,
| Номенклатура.Артикул КАК Артикул,
| ЗначенияСвойств.Значение КАК ТекущийСтатус
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойств
| ПО ЗначенияСвойств.Объект = Номенклатура.Ссылка
| И ЗначенияСвойств.Свойство = &Свойство
|ГДЕ
| Номенклатура.ЭтоГруппа = ЛОЖЬ";
Запрос.УстановитьПараметр("Свойство", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Статус", Истина));
Результат = Запрос.Выполнить().Выгрузить();
Для записи или обновления одиночного значения свойства объекта в регистре сведений ЗначенияСвойствОбъектов используется объект РегистрСведенийМенеджерЗаписи.
Разберем по шагам правильный алгоритм записи:
ПланыВидовХарактеристик.СвойстваОбъектов.Значение свойства имеет ссылочный тип (например, СправочникСсылка.ЗначенияСвойствОбъектов), получаем ссылку на конкретное значение с отбором по владельцу.Объект и Свойство).Значение и вызываем метод Записать(Истина).Посмотрим на пример правильной установки значения свойства:
ВидСвойства = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Статус", Истина);
// Инициализируем менеджер записи
МенеджерЗаписи = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = СсылкаНаНоменклатуру;
МенеджерЗаписи.Свойство = ВидСвойства;
// Если тип значения - строка или примитивный тип:
МенеджерЗаписи.Значение = "Базовый";
// Выполняем запись с замещением
МенеджерЗаписи.Записать(Истина);
Важное замечание: Вызов метода МенеджерЗаписи.Прочитать() имеет смысл только тогда, когда ключевые измерения Объект и Свойство уже заполнены. Вызов Прочитать() до установки измерений не выполняет чтения конкретной записи.
При обходе табличных частей или коллекций через цикл Для частой ошибкой является выход за границы массива из-за неправильно указанной верхней границы:
// Ошибочный вариант:
Для ТекСтрока = 0 По Таблица.Количество() Цикл
// Вызовет ошибку: Индекс находится за границами массива
Строка = Таблица[ТекСтрока];
КонецЦикла;
// Правильный вариант с учетом индексации с 0:
Для ТекСтрока = 0 По Таблица.Количество() - 1 Цикл
Строка = Таблица[ТекСтрока];
КонецЦикла;
// Рекомендуемый вариант обхода элементов:
Для Каждого ТекСтрока Из Таблица Цикл
// Работа с ТекСтрока напрямую
КонецЦикла;
При работе с механизмами свойств и категорий в 1С придерживайтесь следующих правил:
Объект и Свойство требуют ссылочные типы данных, а не строки.НайтиПоНаименованию("Наименование", Истина).Записать(Истина).