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

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

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

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

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

Выбор инструмента зависит от структуры регистра. Для независимого регистра, где запись однозначно определяется значениями измерений (и периодом, если регистр периодический), удобнее всего менеджер записи. Если нужно массово изменить несколько записей или регистр подчинён регистратору, используют набор записей.

Ниже разобраны оба подхода с готовыми примерами кода, типовыми ошибками и способами проверки результата. Примеры приведены на встроенном языке 1С и подходят для управляемых и обычных форм.

Как устроено изменение записи регистра сведений

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

Есть два объектных механизма. РегистрыСведений.ИмяРегистра.СоздатьМенеджерЗаписи() работает с одной записью и подходит для точечных правок. РегистрыСведений.ИмяРегистра.СоздатьНаборЗаписей() оперирует коллекцией записей, отобранных по условиям, и позволяет менять, добавлять и удалять строки пакетно.

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

Изменение одной записи через менеджер записи

Типовой сценарий: нужно изменить цену конкретной номенклатуры в независимом регистре сведений «ЦеныНоменклатуры» с измерением «Номенклатура» и ресурсом «Цена».

МенеджерЗаписи = РегистрыСведений.ЦеныНоменклатуры.СоздатьМенеджерЗаписи();

МенеджерЗаписи.Номенклатура = НоменклатураСсылка;

МенеджерЗаписи.Прочитать();

Если МенеджерЗаписи.Выбран() Тогда

МенеджерЗаписи.Цена = НоваяЦена;

МенеджерЗаписи.Записать();

Иначе

Сообщить("Запись не найдена");

КонецЕсли;

Ключевой момент — проверка Выбран() после чтения. Если записи с таким ключом нет, менеджер останется пустым, и вызов Записать() создаст новую запись вместо изменения существующей. Иногда это именно то, что нужно (поведение «изменить или добавить»), но делать это стоит осознанно.

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

МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();

МенеджерЗаписи.Период = ДатаКурса;

МенеджерЗаписи.Валюта = ВалютаСсылка;

МенеджерЗаписи.Прочитать();

Если МенеджерЗаписи.Выбран() Тогда

МенеджерЗаписи.Курс = НовыйКурс;

МенеджерЗаписи.Записать();

КонецЕсли;

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

Массовое изменение через набор записей

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

НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();

НаборЗаписей.Отбор.ТипЦен.Установить(ТипЦенСсылка);

НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл

Запись.Цена = Запись.Цена * 1.1;

КонецЦикла;

НаборЗаписей.Записать();

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

Если условие не сводится к равенству измерений, сначала выполняют запрос, а затем правят каждую найденную запись через менеджер записи или формируют набор вручную:

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

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

"ВЫБРАТЬ

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

| Цены.Цена КАК Цена

|ИЗ

| РегистрСведений.ЦеныНоменклатуры КАК Цены

|ГДЕ

| Цены.Цена < &МинимальнаяЦена";

Запрос.УстановитьПараметр("МинимальнаяЦена", 100);

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

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

МенеджерЗаписи = РегистрыСведений.ЦеныНоменклатуры.СоздатьМенеджерЗаписи();

МенеджерЗаписи.Номенклатура = Выборка.Номенклатура;

МенеджерЗаписи.Прочитать();

Если МенеджерЗаписи.Выбран() Тогда

МенеджерЗаписи.Цена = 100;

МенеджерЗаписи.Записать();

КонецЕсли;

КонецЦикла;

Особенности регистров, подчинённых регистратору

Если регистр сведений подчинён регистратору (режим записи «Подчинение регистратору»), его записи принадлежат документам и изменяются вместе с движениями документа. Программно такие записи правят через набор записей с отбором по регистратору:

НаборЗаписей = РегистрыСведений.СтатусыДокументов.СоздатьНаборЗаписей();

НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);

НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл

Запись.Статус = Перечисления.Статусы.Согласован;

КонецЦикла;

НаборЗаписей.Записать();

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

Менеджер записи или набор записей

Менеджер записи

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

Набор записей с отбором

Подходит для массовых изменений и регистров с регистратором. Требует обязательного Прочитать() перед Записать(), иначе данные будут потеряны.

Запрос + менеджер записи

Подходит при сложных условиях отбора. Гибко, но медленнее набора на больших объёмах из-за построчной записи.

Транзакции и производительность

При массовых изменениях все правки следует выполнять в транзакции: при ошибке на середине цикла база не останется в частично обновлённом состоянии. Встроенный язык предоставляет методы НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию().

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

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

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

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

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

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

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

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

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

Значение ресурса после записи
Норма

Повторное чтение возвращает новое значение

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

Возвращается старое значение или запись не найдена

Количество записей под отбором
Норма

Совпадает с количеством до обработки (при изменении, а не удалении)

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

Записей стало меньше — вероятно, набор записали без Прочитать()

Движения документа
Норма

После перепроведения документа данные соответствуют логике проведения

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

Ручные правки исчезли после перепроведения

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

Можно ли изменить значение измерения существующей записи?

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

Как удалить запись регистра сведений программно?

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

Почему после Записать() данные в форме не обновились?

Форма списка регистра кэширует данные. Нужно обновить содержимое формы программно (Элементы.Список.Обновить()) или переоткрыть форму. Само значение в базе при этом обычно записано корректно — проверьте запросом.

Как изменить записи регистра без регистрации в обмене данными?

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

Что делать, если Записать() выдаёт ошибку блокировки?

Ошибка «Конфликт блокировок» означает, что другой сеанс уже изменяет те же записи. В серверном коде оборачивайте запись в попытку с повторными попытками или сокращайте длительность транзакции. В регламентных заданиях конфликтующие обработки стоит разводить по расписанию.

Можно ли изменить запись регистра сведений через запрос напрямую?

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

Итог

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

Одну запись независимого регистра меняют через менеджер записи с проверкой Выбран(), массовые правки и регистры с регистратором — через набор записей с обязательным Прочитать() перед Записать(). Сложные условия отбора решают связкой запроса и менеджера записи. Массовые обработки выполняйте в транзакции и предварительно проверяйте на копии базы.