Как правильно получить и записать значение дополнительного свойства номенклатуры в 1С?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке обработок и отчетов в конфигурациях 1С (таких как Управление торговлей 10.3, УПП 1.3 или комплексных системах) часто возникает задача чтения и программной установки дополнительных свойств объектов. Начинающие разработчики нередко сталкиваются с ситуацией, когда запрос к регистру сведений ЗначенияСвойствОбъектов не возвращает данных, хотя в базе они присутствуют.

Разберем по шагам, почему возникают подобные ошибки, как правильно передавать параметры в запрос и как корректно выполнять запись новых значений свойств.

Причина 1: Передача строкового значения вместо ссылки на свойство

Проанализируем исходный код функции получения значения свойства:


Функция ПолучитьЗначениеСвойства(Объект, Свойство)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    ЗначенияСвойствОбъектов.Значение КАК ЗначениеСвойства
        |ИЗ
        |    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
        |ГДЕ
        |    ЗначенияСвойствОбъектов.Объект = &Объект
        |    И ЗначенияСвойствОбъектов.Свойство = &Свойство";
    
    Запрос.УстановитьПараметр("Объект", Объект);
    Запрос.УстановитьПараметр("Свойство", Свойство);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        Возврат Выборка.ЗначениеСвойства;
    КонецЕсли;
    
    Возврат Неопределено;
КонецФункции

Если вызвать данную функцию, передав в качестве параметра строку вида "Статус":

ТекущийСтатус = ПолучитьЗначениеСвойства(Выборка.Номенклатура, "Статус");

Запрос вернет пустой результат. Выясним причину: измерение Свойство регистра сведений ЗначенияСвойствОбъектов имеет ссылочный тип ПланВидовХарактеристикСсылка.СвойстваОбъектов (или ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения в конфигурациях на базе БСП), а не тип Строка.

Чтобы запрос отработал корректно, необходимо передавать ссылку на элемент плана видов характеристик:


СвойствоСсылка = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Статус", Истина);
ТекущийСтатус = ПолучитьЗначениеСвойства(Выборка.Номенклатура, СвойствоСсылка);

Причина 2: Несоответствие типа параметра «Объект»

Вторая частая ошибка — передача в параметр &Объект строкового наименования или другого неподходящего типа вместо ссылки на справочник Справочники.Номенклатура.

Измерение Объект в регистре сведений типизировано ссылками на объекты метаданных. Если в выборке или таблице содержится строка, перед передачей параметра необходимо получить ссылку:


СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоНаименованию(Выборка.Номенклатура, Истина);
ТекущийСтатус = ПолучитьЗначениеСвойства(СсылкаНоменклатура, СвойствоСсылка);

Оптимизация: Избавление от запросов в цикле

Вызов отдельной функции с запросом внутри цикла обхода строк — критическая ошибка производительности. При обработке большого количества строк номенклатуры обращение к базе данных в цикле существенно замедляет работу системы.

Рассмотрим, как объединить получение данных и свойств в один запрос с помощью ЛЕВОЕ СОЕДИНЕНИЕ:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Номенклатура,
    |    Номенклатура.Артикул КАК Артикул,
    |    ЗначенияСвойств.Значение КАК ТекущийСтатус
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойств
    |        ПО ЗначенияСвойств.Объект = Номенклатура.Ссылка
    |        И ЗначенияСвойств.Свойство = &Свойство
    |ГДЕ
    |    Номенклатура.ЭтоГруппа = ЛОЖЬ";

Запрос.УстановитьПараметр("Свойство", ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Статус", Истина));
Результат = Запрос.Выполнить().Выгрузить();

Как программно записать значение свойства

Для записи или обновления одиночного значения свойства объекта в регистре сведений ЗначенияСвойствОбъектов используется объект РегистрСведенийМенеджерЗаписи.

Разберем по шагам правильный алгоритм записи:

  1. Получаем ссылку на свойство объекта через ПланыВидовХарактеристик.СвойстваОбъектов.
  2. Если ресурс Значение свойства имеет ссылочный тип (например, СправочникСсылка.ЗначенияСвойствОбъектов), получаем ссылку на конкретное значение с отбором по владельцу.
  3. Создаем менеджер записи регистра сведений, заполняем ключевые поля измерений (Объект и Свойство).
  4. Устанавливаем ресурс Значение и вызываем метод Записать(Истина).

Посмотрим на пример правильной установки значения свойства:


ВидСвойства = ПланыВидовХарактеристик.СвойстваОбъектов.НайтиПоНаименованию("Статус", Истина);

// Инициализируем менеджер записи
МенеджерЗаписи = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = СсылкаНаНоменклатуру;
МенеджерЗаписи.Свойство = ВидСвойства;

// Если тип значения - строка или примитивный тип:
МенеджерЗаписи.Значение = "Базовый";

// Выполняем запись с замещением
МенеджерЗаписи.Записать(Истина);

Важное замечание: Вызов метода МенеджерЗаписи.Прочитать() имеет смысл только тогда, когда ключевые измерения Объект и Свойство уже заполнены. Вызов Прочитать() до установки измерений не выполняет чтения конкретной записи.

Ошибки при обходе коллекций по индексу

При обходе табличных частей или коллекций через цикл Для частой ошибкой является выход за границы массива из-за неправильно указанной верхней границы:


// Ошибочный вариант:
Для ТекСтрока = 0 По Таблица.Количество() Цикл
    // Вызовет ошибку: Индекс находится за границами массива
    Строка = Таблица[ТекСтрока];
КонецЦикла;

// Правильный вариант с учетом индексации с 0:
Для ТекСтрока = 0 По Таблица.Количество() - 1 Цикл
    Строка = Таблица[ТекСтрока];
КонецЦикла;

// Рекомендуемый вариант обхода элементов:
Для Каждого ТекСтрока Из Таблица Цикл
    // Работа с ТекСтрока напрямую
КонецЦикла;

Итоги

При работе с механизмами свойств и категорий в 1С придерживайтесь следующих правил:

  1. Всегда проверяйте типы передаваемых параметров: измерения Объект и Свойство требуют ссылочные типы данных, а не строки.
  2. Для поиска элементов по наименованию всегда указывайте точное соответствие: НайтиПоНаименованию("Наименование", Истина).
  3. Избегайте выполнения запросов и операций поиска в цикле — получайте свойства через соединения в едином запросе.
  4. Для записи значений в регистры сведений используйте менеджер записи с флагом замещения Записать(Истина).
← На главную