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