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

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с современными конфигурациями 1С на платформе 8.3 (такими как УТ 11, ERP 2, КА 2 или БП 3.0) часто возникает задача массовой очистки или удаления определенных дополнительных реквизитов — для этого есть обработка массового изменения дополнительных реквизитов номенклатуры. Например, когда нужно убрать значение «Черный» у свойства «Цвет» для всей номенклатуры определенной категории. Рассмотрим подробнее, как это реализовать программно, проанализируем типичные ошибки и разберем наиболее эффективные методы решения этой задачи.

Постановка задачи и архитектура данных

Прежде чем переходить к коду, проанализируем, где именно хранятся эти данные. В системе 1С «Дополнительные реквизиты» являются строками табличной части ДополнительныеРеквизиты конкретного справочника (в нашем случае Справочник.Номенклатура). Каждая строка этой таблицы содержит два ключевых поля:

Наша цель — не удалить само «Свойство» из системы, а убрать информацию о нем из конкретных карточек товаров, так же как происходит перенос штрихкодов и упаковок из одной номенклатуры в другую.

Метод 1. Прямое удаление строки из табличной части (через объект)

Рассмотрим самый распространенный способ (или используйте профессиональный менеджер редактирования данных (удобно через универсальный менеджер массового редактирования данных 1С)), который обсуждался на форуме. Он заключается в поиске объектов номенклатуры, содержащих нужное значение, и последующем редактировании их табличной части.

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

  1. Формируем запрос (или используем групповое изменение реквизитов с загрузкой списка) для поиска всей номенклатуры, у которой заполнен целевой реквизит.
  2. В цикле получаем объект каждого найденного элемента.
  3. Находим в табличной части нужную строку (по аналогии с групповым изменением текстовых реквизитов и групп элементов).
  4. Удаляем строку или очищаем её значение.
  5. Записываем объект.

Посмотрим на пример кода, который реализует этот подход:


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

КонецПроцедуры

Важный нюанс: Обратите внимание, что в запросе мы используем отбор и по полю Свойство, и по полю Значение. Поиск только по значению (например, «Черный») опасен, так как это значение может использоваться в разных свойствах («Цвет ткани», «Цвет подкладки»), и вы рискуете очистить лишние данные.

Метод 2. Использование механизмов БСП (Библиотеки стандартных подсистем)

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

Выясним причину, почему это лучше: методы БСП автоматически проверяют права доступа, обновляют необходимые кэши и корректно работают с наборами дополнительных реквизитов. Если мы просто удалим строку, но свойство является обязательным для заполнения в данной категории, система может выдать ошибку при следующем открытии карточки пользователем.

Пример использования БСП для записи свойств:


// Подготовим структуру со значениями реквизитов, которые нужно обновить
ТаблицаСвойств = Новый ТаблицаЗначений;
ТаблицаСвойств.Колонки.Добавить("Свойство");
ТаблицаСвойств.Колонки.Добавить("Значение");

// Если мы хотим «удалить» значение, передаем пустую ссылку соответствующего типа
НоваяСтрока = ТаблицаСвойств.Добавить();
НоваяСтрока.Свойство = НужноеСвойство;
НоваяСтрока.Значение = Неопределено; // Или пустая ссылка

// Вызов стандартного метода БСП
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНаНоменклатуру, ТаблицаСвойств);

Метод 3. Массовое изменение через дополнительные сведения

Иногда пользователи путают «Дополнительные реквизиты» и «Дополнительные сведения». Если ваш реквизит хранится не в табличной части справочника, а в отдельном регистре, то код выше не сработает. Проанализируем ситуацию: дополнительные сведения хранятся в регистре сведений ДополнительныеСведения — для этого подойдёт обработка массового редактирования записей регистров сведений.

Для их удаления нужно работать непосредственно с набором записей регистра:


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

Если МенеджерЗаписи.Выбран() Тогда
    МенеджерЗаписи.Удалить();
КонецЕсли;

Оптимизация производительности при больших объемах

Если в вашей базе данных сотни тысяч позиций номенклатуры, использование ПолучитьОбъект() в цикле приведет к значительным блокировкам и медленной работе. Проанализируем, как ускорить этот процесс:

Рассмотрим пример с использованием транзакции и отключением проверок:


НачатьТранзакцию();
Счетчик = 0;

Пока Выборка.Следующий() Цикл
    Объект = Выборка.Ссылка.ПолучитьОбъект();
    // Логика удаления строк в ТЧ...
    
    Объект.ОбменДанными.Загрузка = Истина;
    Объект.Записать();
    
    Счетчик = Счетчик + 1;
    Если Счетчик % 500 = 0 Тогда
        ЗафиксироватьТранзакцию();
        НачатьТранзакцию();
    КонецЕсли;
КонецЦикла;

ЗафиксироватьТранзакцию();

Типичные ошибки, которых следует избегать

Проанализируем основные промахи начинающих разработчиков при решении этой задачи:

  1. Удаление в «прямом» цикле: Если вы перебираете табличную часть циклом Для Каждого... и внутри него вызываете Удалить(), индексы строк смещаются, и некоторые строки могут быть пропущены. Всегда используйте НайтиСтроки() или обход с конца (счетчик от Количество() - 1 до 0).
  2. Очистка только Значения: Если вы просто очистите поле Значение, но оставите строку в табличной части, это бесполезно увеличит размер базы данных. Лучше полностью удалять строку, если свойство не используется.
  3. Отсутствие вызова ОповеститьОбИзменении: После массового программного изменения данных формы списков (например, список товаров) могут показывать старые данные из кэша. Используйте метод ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура")) на клиенте после завершения работы обработки.

Таким образом, мы рассмотрели различные способы очистки дополнительных реквизитов. Выбор конкретного метода зависит от архитектуры вашей конфигурации и объема данных. Использование штатных средств БСП является наиболее безопасным, в то время как прямая работа с объектом через запросы дает максимальную гибкость при реализации сложных условий отбора.

← На главную