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

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

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

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

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

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

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

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

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

СсылкаКонтрагент = Справочники.Контрагенты.НайтиПоКоду("000000123");

Если СсылкаКонтрагент.Пустая() Тогда

// элемент не найден — создаём новый или пропускаем

КонецЕсли;

Если код неизвестен или неуникален, используйте поиск по наименованию или по произвольному реквизиту:

СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоНаименованию("Кабель ВВГ 3х2,5", Истина);

СсылкаПоИНН = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", "7712345678");

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

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

Ссылка сама по себе доступна только для чтения реквизитов. Чтобы изменить данные, нужно получить объект — полную копию элемента в памяти:

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

ОбъектКонтрагент.НаименованиеПолное = "ООО «Ромашка» (обновлено)";

ОбъектКонтрагент.Комментарий = "Изменено обработкой загрузки";

ОбъектКонтрагент.Записать();

Если элемент имеет табличные части, они доступны через объект как коллекции. Можно очищать, добавлять и изменять строки:

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

ОбъектНоменклатура.ДополнительныеРеквизиты.Очистить();

НоваяСтрока = ОбъектНоменклатура.ДополнительныеРеквизиты.Добавить();

НоваяСтрока.Свойство = СвойствоЦвет;

НоваяСтрока.Значение = "Синий";

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

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

Создание нового элемента и защита от дублей

Частая ситуация: обработка должна изменить элемент, а если его нет — создать. Каркас выглядит так:

СсылкаЭлемент = Справочники.ЕдиницыИзмерения.НайтиПоКоду("796");

Если СсылкаЭлемент.Пустая() Тогда

ОбъектЭлемент = Справочники.ЕдиницыИзмерения.СоздатьЭлемент();

ОбъектЭлемент.Код = "796";

Иначе

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

КонецЕсли;

ОбъектЭлемент.Наименование = "шт";

ОбъектЭлемент.Записать();

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

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

Запись: режимы, проверки и события

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

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

ОбъектЭлемент.ОбменДанными.Загрузка = Истина;

ОбъектЭлемент.Записать();

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

Массовое изменение и транзакции

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

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

Попытка

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

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

ОбъектЭлемент.СтавкаНДС = НоваяСтавка;

ОбъектЭлемент.Записать();

КонецЦикла;

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

Исключение

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

ЗаписьЖурналаРегистрации("МассовоеИзменение", УровеньЖурналаРегистрации.Ошибка,,,

ОписаниеОшибки());

ВызватьИсключение;

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

У длинной транзакции есть обратная сторона: она держит блокировки на всех изменённых элементах до фиксации. В многопользовательской базе это может вызвать конфликты и таймауты у пользователей. Практичный компромисс — разбивать обработку на порции (например, по 100–500 элементов) с фиксацией транзакции на каждую порцию и журналированием прогресса, чтобы при сбое продолжить с места остановки.

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

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

Предопределённые элементы

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

Подчинённые справочники

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

ОбъектЕдиница = Справочники.ЕдиницыИзмерения.СоздатьЭлемент();

ОбъектЕдиница.Владелец = СсылкаНоменклатура;

ОбъектЕдиница.Наименование = "упак";

ОбъектЕдиница.Записать();

Проверка результата и диагностика проблем

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

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

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

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

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

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

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

Открытие элемента в форме
Норма

Форма открывается, реквизиты заполнены новыми значениями

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

Ошибки при открытии или пустые обязательные поля — признак записи в режиме загрузки без контроля

Журнал регистрации
Норма

Нет ошибок за период выполнения обработки

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

Ошибки Отказ в событиях ПередЗаписью или конфликты блокировок

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

Ответы на частые вопросы

Можно ли изменить элемент справочника без ПолучитьОбъект()?

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

Почему ПолучитьОбъект() вызывает ошибку?

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

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

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

Как программно пометить элемент на удаление?

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

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

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

Итог

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

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