При работе с современными конфигурациями 1С на платформе 8.3 (такими как УТ 11, ERP 2, КА 2 или БП 3.0) часто возникает задача массовой очистки или удаления определенных дополнительных реквизитов — для этого есть обработка массового изменения дополнительных реквизитов номенклатуры. Например, когда нужно убрать значение «Черный» у свойства «Цвет» для всей номенклатуры определенной категории. Рассмотрим подробнее, как это реализовать программно, проанализируем типичные ошибки и разберем наиболее эффективные методы решения этой задачи.
Прежде чем переходить к коду, проанализируем, где именно хранятся эти данные. В системе 1С «Дополнительные реквизиты» являются строками табличной части ДополнительныеРеквизиты конкретного справочника (в нашем случае Справочник.Номенклатура). Каждая строка этой таблицы содержит два ключевых поля:
Наша цель — не удалить само «Свойство» из системы, а убрать информацию о нем из конкретных карточек товаров, так же как происходит перенос штрихкодов и упаковок из одной номенклатуры в другую.
Рассмотрим самый распространенный способ (или используйте профессиональный менеджер редактирования данных (удобно через универсальный менеджер массового редактирования данных 1С)), который обсуждался на форуме. Он заключается в поиске объектов номенклатуры, содержащих нужное значение, и последующем редактировании их табличной части.
Разберем по шагам правильный алгоритм реализации этой задачи:
Посмотрим на пример кода, который реализует этот подход:
Процедура ОчиститьДопРеквизитНаСервере(ВыбранноеСвойство, ВыбранноеЗначение)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НоменклатураДополнительныеРеквизиты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
|ГДЕ
| НоменклатураДополнительныеРеквизиты.Свойство = &Свойство
| И НоменклатураДополнительныеРеквизиты.Значение = &Значение";
Запрос.УстановитьПараметр("Свойство", ВыбранноеСвойство);
Запрос.УстановитьПараметр("Значение", ВыбранноеЗначение);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
НоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
// Поиск строк, соответствующих нашему свойству
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Свойство", ВыбранноеСвойство);
ПараметрыОтбора.Вставить("Значение", ВыбранноеЗначение);
НайденныеСтроки = НоменклатураОбъект.ДополнительныеРеквизиты.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаРеквизита Из НайденныеСтроки Цикл
// Вариант А: Полное удаление строки (рекомендуется)
НоменклатураОбъект.ДополнительныеРеквизиты.Удалить(СтрокаРеквизита);
// Вариант Б: Просто очистка значения, если нужно оставить строку
// СтрокаРеквизита.Значение = Справочники.ЗначенияСвойствОбъектов.ПустаяСсылка();
КонецЦикла;
Если НайденныеСтроки.Количество() > 0 Тогда
НоменклатураОбъект.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: Обратите внимание, что в запросе мы используем отбор и по полю Свойство, и по полю Значение. Поиск только по значению (например, «Черный») опасен, так как это значение может использоваться в разных свойствах («Цвет ткани», «Цвет подкладки»), и вы рискуете очистить лишние данные.
В современных конфигурациях 1С работа со свойствами жестко регламентирована. Использование стандартного метода ПолучитьОбъект() и прямой записи может быть неоптимальным, если объектов очень много. Правильнее использовать программный интерфейс БСП, в частности модуль УправлениеСвойствами.
Выясним причину, почему это лучше: методы БСП автоматически проверяют права доступа, обновляют необходимые кэши и корректно работают с наборами дополнительных реквизитов. Если мы просто удалим строку, но свойство является обязательным для заполнения в данной категории, система может выдать ошибку при следующем открытии карточки пользователем.
Пример использования БСП для записи свойств:
// Подготовим структуру со значениями реквизитов, которые нужно обновить
ТаблицаСвойств = Новый ТаблицаЗначений;
ТаблицаСвойств.Колонки.Добавить("Свойство");
ТаблицаСвойств.Колонки.Добавить("Значение");
// Если мы хотим «удалить» значение, передаем пустую ссылку соответствующего типа
НоваяСтрока = ТаблицаСвойств.Добавить();
НоваяСтрока.Свойство = НужноеСвойство;
НоваяСтрока.Значение = Неопределено; // Или пустая ссылка
// Вызов стандартного метода БСП
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНаНоменклатуру, ТаблицаСвойств);
Иногда пользователи путают «Дополнительные реквизиты» и «Дополнительные сведения». Если ваш реквизит хранится не в табличной части справочника, а в отдельном регистре, то код выше не сработает. Проанализируем ситуацию: дополнительные сведения хранятся в регистре сведений ДополнительныеСведения — для этого подойдёт обработка массового редактирования записей регистров сведений.
Для их удаления нужно работать непосредственно с набором записей регистра:
МенеджерЗаписи = РегистрыСведений.ДополнительныеСведения.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = СсылкаНаНоменклатуру;
МенеджерЗаписи.Свойство = НужноеСвойство;
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Удалить();
КонецЕсли;
Если в вашей базе данных сотни тысяч позиций номенклатуры, использование ПолучитьОбъект() в цикле приведет к значительным блокировкам и медленной работе. Проанализируем, как ускорить этот процесс:
ОбменДанными.Загрузка = Истина, чтобы отключить лишние проверки и ускорить запись.Рассмотрим пример с использованием транзакции и отключением проверок:
НачатьТранзакцию();
Счетчик = 0;
Пока Выборка.Следующий() Цикл
Объект = Выборка.Ссылка.ПолучитьОбъект();
// Логика удаления строк в ТЧ...
Объект.ОбменДанными.Загрузка = Истина;
Объект.Записать();
Счетчик = Счетчик + 1;
Если Счетчик % 500 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Проанализируем основные промахи начинающих разработчиков при решении этой задачи:
Для Каждого... и внутри него вызываете Удалить(), индексы строк смещаются, и некоторые строки могут быть пропущены. Всегда используйте НайтиСтроки() или обход с конца (счетчик от Количество() - 1 до 0).Значение, но оставите строку в табличной части, это бесполезно увеличит размер базы данных. Лучше полностью удалять строку, если свойство не используется.ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура")) на клиенте после завершения работы обработки.Таким образом, мы рассмотрели различные способы очистки дополнительных реквизитов. Выбор конкретного метода зависит от архитектуры вашей конфигурации и объема данных. Использование штатных средств БСП является наиболее безопасным, в то время как прямая работа с объектом через запросы дает максимальную гибкость при реализации сложных условий отбора.