Разработка и Конфигурация · 13 мин
Как программно изменить регистр сведений в 1С
Как программно изменить регистр сведений в 1С: наборы записей, менеджеры записи, отборы, периодические регистры. Примеры кода, типичные ошибки, FAQ.
Регистр сведений в 1С хранит данные в разрезе измерений и, при необходимости, периода: курсы валют, цены номенклатуры, ответственных лиц, настройки обменов. Программное изменение такого регистра — рутинная задача при загрузке данных, исправлении ошибок и автоматизации учёта, и у неё есть два основных инструмента: набор записей (РегистрыСведений.Имя.СоздатьНаборЗаписей()) и менеджер записи (СоздатьМенеджерЗаписи()).
Выбор инструмента зависит от режима регистра. Для независимого регистра сведений обычно работают набором записей с отбором по измерениям — это единственный способ изменить сразу несколько строк. Менеджер записи удобен, когда нужно точечно прочитать, изменить или удалить одну запись, но он неприменим к регистрам, подчинённым регистратору, — там запись существует только внутри движений документа.
Неправильное изменение регистра способно нарушить логику учёта: например, массовая запись без отбора затрёт все существующие строки, а изменение подчинённого регистра в обход документа разорвёт связь движений с регистратором. Ниже — конкретные приёмы с кодом, проверкой результата и типичными ошибками.
Как устроен регистр сведений и что это меняет для записи
Структура регистра определяет, как именно его можно изменить. Независимый регистр сведений хранит строки, уникальные по комбинации измерений (и периода, если регистр периодический). Записать в него можно напрямую, без документа. Регистр, подчинённый регистратору, заполняется только движениями документа: каждая строка привязана к полю «Регистратор», и прямой вызов Записать() для произвольного набора не сработает корректно.
Периодичность тоже влияет на подход. В периодическом регистре ключ записи — это измерения плюс дата, поэтому при изменении нужно указывать период, иначе отбор не найдёт нужную строку или создаст дубль на другую дату. Режим «В пределах секунды/дня/месяца» определяет точность ключа.
Перед изменением откройте регистр в конфигураторе и уточните: режим записи (независимый или подчинённый), периодичность, состав измерений, ресурсов и реквизитов. Имена этих полей понадобятся в коде отбора и присвоения значений.
Изменение записей через набор записей
Универсальный способ для независимого регистра — набор записей с отбором. Отбор обязателен: без него запись набора заменит все строки регистра, что почти всегда является ошибкой и может привести к потере данных.
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(НоменклатураСсылка);
НаборЗаписей.Отбор.ТипЦен.Установить(ТипЦенСсылка);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() > 0 Тогда
Запись = НаборЗаписей[0];
Запись.Цена = НоваяЦена;
Иначе
Запись = НаборЗаписей.Добавить();
Запись.Номенклатура = НоменклатураСсылка;
Запись.ТипЦен = ТипЦенСсылка;
Запись.Цена = НоваяЦена;
КонецЕсли;
НаборЗаписей.Записать();
Логика «прочитать — изменить или добавить — записать» безопасна: существующая строка обновляется, отсутствующая создаётся. Если нужно именно удалить записи по условию, достаточно установить отбор и вызвать НаборЗаписей.Записать() без чтения и добавления — пустой набор сотрёт строки, попадающие под отбор.
Для массового изменения по одному измерению (например, пересчитать все цены одного типа) установите отбор только по этому измерению, прочитайте набор, пройдите циклом по строкам и измените ресурс. Один вызов Записать() зафиксирует все изменения разом, что быстрее, чем запись каждой строки отдельно.
Работа с одной записью через менеджер записи
Менеджер записи представляет ровно одну строку независимого регистра. Он удобен, когда известен полный ключ: все измерения и период для периодического регистра. Типовой сценарий — прочитать значения в структуру менеджера, изменить ресурс и записать.
МенеджерЗаписи = РегистрыСведений.ОтветственныеЛица.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Организация = ОрганизацияСсылка;
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Сотрудник = НовыйОтветственный;
МенеджерЗаписи.Записать();
Иначе
// Записи с таким ключом нет — создаём новую
МенеджерЗаписи.Организация = ОрганизацияСсылка;
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.Сотрудник = НовыйОтветственный;
МенеджерЗаписи.Записать();
КонецЕсли;
Проверка Выбран() обязательна: без неё невозможно отличить «записи нет» от «запись есть, но ресурсы пустые». Для удаления одиночной записи используется метод Удалить() менеджера после заполнения ключа.
Ограничение метода: менеджер записи не работает с регистрами, подчинёнными регистратору, и не подходит для массовых операций — каждая запись требует отдельного обращения к базе.
Особенности периодических регистров сведений
В периодическом регистре одна и та же комбинация измерений может иметь много строк на разные даты. Поэтому при изменении всегда задавайте период в отборе или в ключе менеджера записи, иначе рискуете создать дубль: новую строку с текущей датой вместо правки существующей.
Чтобы получить актуальное значение на дату, используйте виртуальную таблицу СрезПоследних в запросе, а не перебор записей. Для изменения истории (например, исправить цену задним числом) отбирайте набор по измерениям и периоду конкретной строки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Курсы.Курс
|ИЗ
| РегистрСведений.КурсыВалют.СрезПоследних(&Период, Валюта = &Валюта) КАК Курсы";
Запрос.УстановитьПараметр("Период", ДатаКурса);
Запрос.УстановитьПараметр("Валюта", ВалютаСсылка);
Результат = Запрос.Выполнить().Выбрать();
Ещё одна особенность: запись на дату, где уже есть строка с тем же ключом, перезапишет её без предупреждения. Это удобно для обновления, но опасно при загрузке истории — проверяйте существование записи через Прочитать() и Выбран() или запросом.
Изменение регистра, подчинённого регистратору
Если регистр сведений подчинён регистратору, его строки принадлежат документам. Программно изменить такой регистр можно только через набор записей с отбором по полю «Регистратор» — фактически через движения конкретного документа:
НаборЗаписей = РегистрыСведений.СтатусыДокументов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
Запись.Статус = НовыйСтатус;
КонецЦикла;
НаборЗаписей.Записать();
Такой приём допустим как техническая корректировка, но он разрывает логику проведения: при следующем перепроведении документ сформирует движения заново и затрёт ручные правки. Корректный путь — изменить данные в самом документе или в его процедуре ОбработкаПроведения и перепровести.
Признак того, что регистр подчинён регистратору: в форме списка есть колонка «Регистратор», а в конфигураторе в свойствах регистра указан режим «Подчинение регистратору». Менеджер записи для такого регистра не используется.
Сравнение вариантов
Подходит для массовых изменений и удаления в независимых регистрах; единственный вариант для регистров с регистратором. Требует аккуратности с отбором.
Точечная правка одной строки по полному ключу. Простой код, но медленно при массовых операциях и недоступен для подчинённых регистров.
Сначала запросом находятся нужные ключи (например, через СрезПоследних), затем каждый ключ обрабатывается набором. Оптимально для сложных условий отбора.
Транзакции, блокировки и производительность
При массовом изменении регистра в многопользовательской базе оборачивайте операции в транзакцию: НачатьТранзакцию() — изменения — ЗафиксироватьТранзакцию(), а в исключении — ОтменитьТранзакцию(). Тогда при ошибке посередине цикла регистр не останется изменённым наполовину.
По возможности сужайте отбор: запись набора блокирует строки, попадающие под отбор, и широкий отбор в часы активной работы пользователей вызовет конфликты блокировок. Большие пакеты изменений разбивайте на порции по несколько тысяч записей с фиксацией транзакции между порциями.
При загрузке данных, когда гарантированно нужно просто заменить содержимое по отбору, используйте НаборЗаписей.Записать(Истина) — параметр «Замещение» по умолчанию и так истина, но явное указание делает намерение понятным. Режим Записать(Ложь) добавляет записи без замещения и вызовет ошибку при совпадении ключей.
- 1Определите в конфигураторе режим регистра: независимый или подчинённый регистратору, периодичность, состав измерений
- 2Сделайте архивную копию базы или проверьте код на тестовой копии
- 3Напишите код с обязательным отбором набора записей и проверкой существования записи
- 4Оберните массовые изменения в транзакцию
- 5Выполните изменение и проверьте результат запросом или формой списка регистра
Проверка результата и типичные ошибки
После записи убедитесь, что изменилось именно то, что планировалось. Откройте регистр через стандартную форму списка с отбором по изменённым измерениям или выполните контрольный запрос: количество строк по отбору до и после должно отличаться предсказуемо. Для периодических регистров проверяйте срез последних — именно его видят большинство механизмов конфигурации.
Косвенный признак успеха — отсутствие исключений при Записать(). Ошибка «Запись с такими ключевыми полями существует» означает попытку добавить дубль при Записать(Ложь) или конфликт уникальности; ошибка блокировки — что данные заняты другим сеансом, повторите попытку или сузьте отбор.
Как проверить результат
Совпадает с ожидаемым: обновление не меняет число строк, добавление увеличивает на число новых ключей
Строк стало меньше — вероятно, отбор был шире и лишние данные затёрты
Возвращается новое значение ресурса на нужную дату
Старое значение — изменена не та строка или не тот период
Для подчинённого регистра значения формируются документом корректно
Ручные правки исчезли — регистр подчинён регистратору, менять нужно через документ
Частые вопросы
Чем отличается Записать(Истина) от Записать(Ложь) у набора записей?
Параметр управляет замещением. Записать(Истина) — режим по умолчанию: набор полностью заменяет строки, попадающие под отбор. Записать(Ложь) добавляет строки без замещения; если ключ новой строки совпадёт с существующей, возникнет ошибка уникальности. Для обновления данных почти всегда используют режим замещения.
Как удалить все записи регистра сведений программно?
Создайте набор записей без отбора и вызовите Записать() — пустой набор очистит весь регистр. Это разрушительная операция: перед ней обязательно сделайте копию базы. Если нужно удалить только часть данных, установите отбор по измерениям и запишите пустой набор с этим отбором.
Можно ли изменить регистр сведений запросом, без набора записей?
Нет. Язык запросов 1С предназначен только для чтения; конструкций UPDATE и DELETE в нём нет. Запрос используют для поиска нужных ключей (например, через СрезПоследних), а само изменение выполняют набором записей или менеджером записи.
Почему менеджер записи не находит существующую строку?
Чаще всего не заполнен какой-то элемент ключа: одно из измерений или период для периодического регистра. Ключ должен совпадать полностью, включая типы значений — например, пустая ссылка другого типа не равна заполненной. Проверьте состав измерений в конфигураторе и значения, которые присваиваются менеджеру перед Прочитать().
Как изменить регистр сведений из внешней обработки?
Точно так же, как из модуля конфигурации: объектная модель регистров доступна в любом серверном коде. Во внешней обработке добавьте кнопку, в серверной процедуре которой выполняется набор записей с отбором. Убедитесь, что у пользователя, запускающего обработку, есть права на изменение этого регистра.
Что делать, если при записи возникает конфликт блокировок?
Конфликт означает, что другой сеанс уже изменяет те же строки. Варианты: повторить попытку через паузу, сузить отбор, выполнять операцию в монопольном режиме или вне рабочего времени. Для массовых загрузок помогает разбиение на порции с отдельными транзакциями — блокировка удерживается короче.
Что важно запомнить
Независимый регистр сведений изменяют набором записей с обязательным отбором или менеджером записи по полному ключу; подчинённый регистратору — только через движения документа. В периодическом регистре всегда указывайте период. Массовые изменения выполняйте в транзакции, предварительно проверив код на копии базы.