К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как удалить номенклатуру в 1С программно

Как программно удалить номенклатуру в 1С: пометка на удаление, Удалить(), контроль ссылочной целостности, обработки для группового удаления и типичные ошибки.

Удаление элементов справочника «Номенклатура» через встроенный язык 1С — типовая задача при чистке базы после тестовых загрузок, исправлении ошибок обмена или выгрузке дублей. Прямое физическое удаление объекта возможно, но почти всегда небезопасно: на товар могут ссылаться документы, регистры и другие справочники, и после удаления база получит «битые» ссылки вида «Объект не найден».

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

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

Два способа удаления: пометка и непосредственное удаление

В платформе 1С существуют два принципиально разных механизма. Первый — пометка на удаление: объект остаётся в базе, но исключается из большинства выборок и отчётов, а физически удаляется позже через специальную операцию «Удаление помеченных объектов». Это безопасный и рекомендуемый путь для любых данных, которые могли использоваться.

Второй механизм — непосредственное удаление методом Удалить() у объекта. Запись стирается из таблицы справочника сразу, без проверки ссылок со стороны платформы (проверка выполняется только если разработчик сам её организовал). Если на элемент ссылался документ, в нём останется «битая» ссылка, которую придётся восстанавливать вручную.

Сравнение вариантов

УстановитьПометкуУдаления(Истина)

Подходит всегда. Объект остаётся в базе, удаляется штатной обработкой с контролем ссылок. Безопасно, обратимо до физического удаления.

Объект.Удалить()

Подходит только для элементов без ссылок (тестовые данные, ошибочная загрузка). Быстро, но необратимо и без контроля целостности.

Обработка «Удаление помеченных объектов»

Финальный этап: физически удаляет помеченное, показывая, где объект используется. Работает и в монопольном, и в частичном режиме.

Пометка на удаление одного элемента программно

Чтобы пометить элемент на удаление из кода, нужно получить объект по ссылке и вызвать метод УстановитьПометкуУдаления(). Метод сам записывает объект, отдельный вызов Записать() не требуется.

Процедура ПометитьНоменклатуру(СсылкаНаЭлемент)

ОбъектНоменклатуры = СсылкаНаЭлемент.ПолучитьОбъект();

Если ОбъектНоменклатуры = Неопределено Тогда

Возврат; // элемент уже физически удалён

КонецЕсли;

ОбъектНоменклатуры.УстановитьПометкуУдаления(Истина);

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

Снять пометку можно тем же методом с параметром Ложь. Обратите внимание: если у справочника включена иерархия и вы помечаете группу, по умолчанию пометка распространяется на подчинённые элементы — это контролируется вторым параметром метода в некоторых контекстах, поэтому проверяйте поведение на тестовой копии.

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

Непосредственное удаление через Удалить()

Метод Удалить() вызывается у объекта справочника и стирает запись физически. Типовой сценарий его применения — очистка после неудачной загрузки из файла или обмена, когда данные гарантированно ещё нигде не использовались.

Процедура УдалитьНоменклатуруНепосредственно(СсылкаНаЭлемент)

ОбъектНоменклатуры = СсылкаНаЭлемент.ПолучитьОбъект();

Если ОбъектНоменклатуры = Неопределено Тогда

Возврат;

КонецЕсли;

ОбъектНоменклатуры.Удалить();

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

Перед вызовом Удалить() имеет смысл самостоятельно проверить, используется ли элемент. Для этого служит функция платформы НайтиПоСсылкам(), которая возвращает таблицу всех мест использования ссылки:

МассивСсылок = Новый Массив;

МассивСсылок.Добавить(СсылкаНаЭлемент);

ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);

Если ТаблицаСсылок.Количество() = 0 Тогда

ОбъектНоменклатуры.Удалить();

Иначе

ОбъектНоменклатуры.УстановитьПометкуУдаления(Истина);

КонецЕсли;

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

Групповое удаление: обработка списка элементов

На практике чаще всего удаляют не один элемент, а выборку — например, все позиции из определённой группы или созданные конкретной загрузкой. Типовой подход: запросом отобрать ссылки, затем в цикле обработать каждую.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Ссылка

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| Номенклатура.Родитель = &Группа

| И НЕ Номенклатура.ПометкаУдаления";

Запрос.УстановитьПараметр("Группа", ГруппаДляОчистки);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

ОбъектНоменклатуры = Выборка.Ссылка.ПолучитьОбъект();

ОбъектНоменклатуры.УстановитьПометкуУдаления(Истина);

КонецЦикла;

Для больших объёмов (десятки тысяч элементов) учитывайте три момента. Во-первых, оборачивайте обработку в транзакцию порциями или полностью — иначе при сбое часть элементов останется в промежуточном состоянии. Во-вторых, на клиент-серверной базе выполняйте код на сервере, внешняя обработка с клиентским вызовом будет работать в разы медленнее. В-третьих, метод НайтиПоСсылкам() для большого массива ссылок выполняется долго — разбивайте массив на порции по несколько сотен элементов.

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

Удаление помеченных объектов и контроль целостности

Пометка на удаление — только половина задачи. Физически данные удаляются штатным механизмом «Удаление помеченных объектов» (в типовых конфигурациях: раздел «Администрирование» → «Обслуживание»). Механизм проверяет ссылочную целостность и показывает, какие объекты удалить нельзя и где они используются.

Программно ту же операцию можно выполнить методом УдалитьПомеченныеОбъекты() — это глобальный метод платформы. Он требует монопольного доступа к базе и в файловом варианте может занимать значительное время. В клиент-серверном варианте монопольный режим устанавливается через УстановитьМонопольныйРежим(Истина).

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

Особые случаи: дубли, предопределённые элементы и обмены

Если задача — убрать дубли номенклатуры, простое удаление не подойдёт: сначала нужно заменить ссылки с дубля на «правильный» элемент во всех документах и регистрах. В типовых конфигурациях для этого есть обработка «Поиск и удаление дублей» (БСП), которая выполняет замену ссылок и помечает дубли. Программно замену делают через НайтиПоСсылкам() с последующей перезаписью найденных объектов.

Предопределённые элементы (созданные в конфигураторе) удалить из пользовательского режима нельзя — платформа выдаст ошибку. Пометить их на удаление тоже не получится, если это запрещено настройками конфигурации. Единственный путь — изменение конфигурации, что выходит за рамки прикладной обработки.

Если база участвует в обмене (РИБ, обмен с сайтом, синхронизация между конфигурациями), пометка на удаление и физическое удаление будут переданы в другие узлы. Это может привести к массовому удалению данных в связанных системах. Перед чисткой отключите регистрацию изменений для узлов обмена или убедитесь, что удаление — желаемое поведение.

Типичные ошибки
01
Вызов Удалить() без НайтиПоСсылкам() — в документах появляются ссылки «Объект не найден», которые ломают отчёты и проведение
02
Запуск обработки без резервной копии — откатить физическое удаление невозможно
03
Игнорирование обменов — пометка на удаление улетает в другие узлы и удаляет данные там
04
Удаление в цикле с вызовом ПолучитьОбъект() на клиенте — обработка десятков тысяч элементов занимает часы вместо минут
05
Попытка удалить предопределённый элемент — ошибка выполнения и остановка обработки посередине

Проверка результата и откат

После выполнения обработки убедитесь в результате тремя проверками. Первая: запросом посчитайте остаток элементов в очищаемой группе — помеченные должны исчезнуть из выборки без отбора по пометке. Вторая: откройте несколько документов, где раньше использовалась удалённая номенклатура, и убедитесь, что ссылки отображаются корректно (если элемент был помечен, а не удалён физически, ссылка останется рабочей). Третья: запустите «Удаление помеченных объектов» и проверьте, что целевые элементы не числятся среди неудалённых из-за ссылок.

Если обнаружились «битые» ссылки после непосредственного удаления, единственный надёжный способ восстановления — откат на резервную копию с последующим повторением чистки правильным способом. Поэтому копия перед операцией — не формальность, а обязательный этап.

Контрольные точки

Как проверить результат

Запрос по справочнику без отбора по пометке
Норма

Удалённые элементы не возвращаются

Тревожный признак

Элементы на месте — пометка не установилась, проверьте права и исключения в коде

Документы, где использовался элемент
Норма

Ссылка открывается, отображается наименование

Тревожный признак

В поле ссылки текст «<Объект не найден>» — элемент удалён физически при наличии ссылок

Список неудалённых при удалении помеченных
Норма

Целевых элементов нет или они ожидаемо используются

Тревожный признак

Элементы не удаляются из-за неочевидных ссылок (регистры сведений, характеристики)

Итог

Что важно запомнить

Безопасный алгоритм один: резервная копия → НайтиПоСсылкам() → Удалить() для чистых элементов и УстановитьПометкуУдаления(Истина) для используемых → штатное удаление помеченных. Непосредственное удаление без проверки ссылок — главный источник повреждённых баз.

Частые вопросы

Можно ли удалить номенклатуру, если она используется в проведённых документах?

Технически метод Удалить() это позволяет, но делать так нельзя: в документах останутся неразрешённые ссылки, нарушатся отчёты и итоги. Корректный вариант — пометить элемент на удаление: данные в документах сохранятся, а элемент исчезнет из выборок. Физически он удалится только после того, как документы будут перепроведены на другую номенклатуру или удалены.

Чем УстановитьПометкуУдаления() отличается от установки реквизита ПометкаУдаления вручную?

Метод УстановитьПометкуУдаления() корректно обрабатывает иерархию и подчинённые объекты, вызывает нужные обработчики и сам записывает объект. Прямая запись в реквизит ПометкаУдаления с последующим Записать() в ряде случаев даст тот же эффект, но не гарантирует каскадной обработки и считается плохой практикой.

Как удалить сразу все элементы справочника «Номенклатура»?

Запросом выберите все ссылки без отборов и в цикле вызовите УстановитьПометкуУдаления(Истина), затем выполните штатное удаление помеченных объектов. Учтите, что физически удалятся только элементы без ссылок — в рабочей базе с историей это обычно малая часть. Полная очистка справочника в базе с документами невозможна без удаления самих документов.

Почему НайтиПоСсылкам() работает очень долго?

Метод сканирует все таблицы конфигурации, где может храниться ссылка. На больших базах и при передаче массива из тысяч ссылок это занимает заметное время. Разбивайте массив на порции по 200–500 ссылок и выполняйте проверку на сервере. Для разовой чистки иногда быстрее пометить всё и положиться на контроль при удалении помеченных.

Можно ли отменить пометку на удаление массово?

Да, тем же способом: выберите запросом элементы с ПометкаУдаления = Истина и в цикле вызовите УстановитьПометкуУдаления(Ложь). Отмена возможна только до физического удаления — после выполнения «Удаления помеченных объектов» восстановить данные можно лишь из резервной копии.

Нужны ли особые права для программного удаления?

Код выполняется с правами текущего пользователя. Если у пользователя нет права «Удаление» или «Интерактивное удаление» на справочник, вызовы завершатся ошибкой нарушения прав доступа. Для служебных обработок используют УстановитьПривилегированныйРежим(Истина), но это должно быть осознанным решением с учётом рисков безопасности.