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

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

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

Как программно изменить реквизит справочника в 1С: получение объекта, запись, обход в цикле, типичные ошибки и проверка результата с примерами кода.

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

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

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

Получаем объект справочника и меняем реквизит

Главный принцип: ссылка на элемент справочника — это только идентификатор, изменять данные через неё нельзя. Чтобы поменять реквизит, нужно получить объект — полноценную копию элемента в памяти, доступную для редактирования. Для этого служит метод ПолучитьОбъект(), вызываемый у ссылки.

Минимальный пример: меняем ставку НДС у конкретной номенклатуры, ссылка на которую уже известна (например, выбрана на форме обработки).

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

НоменклатураОбъект.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;

НоменклатураОбъект.Записать();

Если ссылки нет, элемент находят по коду, наименованию или реквизиту через методы менеджера справочника: Справочники.Номенклатура.НайтиПоКоду("000000123") или НайтиПоНаименованию("Кирпич М-150", Истина). Методы возвращают ссылку; если элемент не найден — пустую ссылку, которую обязательно проверяют через Ссылка.Пустая() перед получением объекта.

После вызова Записать() изменения сохранены в базе. Если метод не вызвать, объект останется изменённым только в памяти и при завершении кода все правки потеряются — это самая частая причина «не срабатывающего» кода.

bsl
ЭлементСсылка = Справочники.Номенклатура.НайтиПоКоду("000000123");
Если Не ЭлементСсылка.Пустая() Тогда
    ЭлементОбъект = ЭлементСсылка.ПолучитьОбъект();
    ЭлементОбъект.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;
    ЭлементОбъект.Записать();
КонецЕсли;

Ссылка и объект: в чём разница и почему это важно

Ссылка (СправочникСсылка) — лёгкий объект-указатель. Через неё можно читать реквизиты «через точку» (платформа неявно выполняет запрос к базе), но присваивание значений полям ссылки недоступно. Попытка написать НоменклатураСсылка.СтавкаНДС = ... вызовет ошибку исполнения.

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

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

Массовое изменение реквизита у группы элементов

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

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

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

"ВЫБРАТЬ

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

|ИЗ

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

|ГДЕ

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

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

Запрос.УстановитьПараметр("Группа", ГруппаТоваров);

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

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

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

ТекОбъект.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;

ТекОбъект.Записать();

КонецЦикла;

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

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

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

Транзакция и обработка ошибок записи

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

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

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

Попытка

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

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

ТекОбъект.СтавкаНДС = Перечисления.СтавкиНДС.НДС20;

ТекОбъект.Записать();

КонецЦикла;

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

Исключение

ОтменитьТранзакцию();

Сообщить("Ошибка записи: " + ОписаниеОшибки());

КонецПопытки;

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

Изменение реквизита на сервере и в фоновом задании

В управляемом приложении код, меняющий данные, должен выполняться на сервере. В модуле формы обработки используют директиву &НаСервере; с клиента серверную процедуру вызывают без передачи объектов — объекты справочников нельзя передавать между клиентом и сервером, передают только ссылки и примитивные типы.

Тяжёлые обработки правильно запускать в фоновом задании через ДлительныеОперации.ВыполнитьВФоне() (в конфигурациях на БСП) или ФоновыеЗадания.Выполнить(). Фоновое выполнение не блокирует интерфейс пользователя и позволяет показывать прогресс и корректно отменять операцию.

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

Как проверить результат и что делать при ошибках

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

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

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

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

Значение реквизита у выборочных элементов
Норма

Открытые вручную элементы содержат новое значение

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

Значение старое — запись не выполнилась или был откат транзакции

Количество изменённых элементов
Норма

Совпадает с числом строк выборки минус ошибки из лога

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

Меньше без зафиксированных ошибок — часть элементов пропущена молча

Блокировки и жалобы пользователей
Норма

Обработка завершилась без конфликтов

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

Конфликты блокировок — нужно снизить объём порции или перенести запуск на нерабочее время

Типичные ошибки при программном изменении реквизитов

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

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

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

Итог

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

Изменение реквизита справочника всегда идёт по схеме: получить объект по ссылке, присвоить значение, вызвать Записать(). Для массовых операций добавьте точный отбор запросом, транзакцию или лог ошибок, фоновое выполнение и обязательную проверку результата на копии базы.

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

Можно ли изменить реквизит без получения объекта?

Нет, запись возможна только через объект. Чтение доступно через ссылку или запрос, но любое изменение требует вызова ПолучитьОбъект() и последующего Записать(). Альтернатива — метод УстановитьЗначениеКонстанты для констант, но к справочникам это не относится.

Как изменить реквизит у всех элементов справочника сразу?

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

Почему Записать() выдаёт ошибку, хотя значение корректное?

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

Как изменить реквизит табличной части элемента?

После получения объекта обратитесь к табличной части как к коллекции: переберите строки циклом Для Каждого Строка Из Объект.ТабличнаяЧасть Цикл, измените поля строк и затем вызовите Записать() у объекта целиком. Отдельной записи у строк табличной части нет — сохраняется весь элемент.

Чем программное изменение отличается от групповой обработки в интерфейсе?

Штатная обработка «Групповое изменение реквизитов» в типовых конфигурациях выполняет ту же операцию без программирования и подходит для разовых задач администратора. Программный код нужен, когда изменение — часть бизнес-логики: обработка по расписанию, сложные условия вычисления значения, интеграция с другими механизмами.

Безопасно ли запускать такую обработку в рабочей базе днём?

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