Разработка и Конфигурация · 12 мин
Как в 1С программно добавить запись в регистр сведений
Как в 1С добавить запись в регистр сведений программно: менеджер записи, набор записей, периодические и подчинённые регистратору регистры, примеры кода и ошибки.
Регистр сведений в 1С хранит информацию в разрезе измерений: курсы валют, цены номенклатуры, адреса контрагентов, настройки пользователей. Программное добавление записи требуется при загрузке данных из внешних источников, при обмене между базами, при заполнении начальных настроек и в обработчиках бизнес-логики. В зависимости от структуры регистра используются два основных механизма: менеджер записи для одиночной строки и набор записей для пакетной работы.
Ключевой фактор выбора способа — режим записи регистра. Независимый регистр сведений позволяет добавлять строки напрямую через РегистрыСведений.ИмяРегистра.СоздатьМенеджерЗаписи() или через набор записей с пустым отбором по регистратору. Регистр, подчинённый регистратору, изменяется только через набор записей, привязанный к конкретному документу, — попытка записать менеджером записи завершится ошибкой.
Ниже разобраны оба подхода с рабочим кодом, особенности периодических регистров, типичные ошибки и способы проверить результат.
Как определить, каким способом записывать регистр
Перед написанием кода откройте регистр в конфигураторе и посмотрите два свойства: «Режим записи» и «Периодичность». Режим записи бывает «Независимый» и «Подчинение регистратору». Периодичность — «Непериодический», «В пределах секунды/дня/месяца/года» и т.д. От этих двух свойств зависит весь дальнейший код.
Независимый регистр допускает оба механизма: менеджер записи и набор записей. Подчинённый регистратору — только набор записей, и обязательно с установленным отбором по регистратору. Периодический регистр требует заполнения поля Период, причём платформа сама приводит его к началу периода (например, к началу дня при периодичности «в пределах дня»).
Как выбрать способ записи
Добавление одиночной записи через менеджер записи
Менеджер записи — самый простой способ добавить или изменить одну строку независимого регистра. Объект создаётся вызовом СоздатьМенеджерЗаписи(), поля заполняются напрямую, затем вызывается метод Записать(). Если запись с таким набором измерений (и периодом для периодического регистра) уже существует, она будет перезаписана — дубль не создастся.
// Пример: запись цены номенклатуры в независимый периодический регистр
МенеджерЗаписи = РегистрыСведений.ЦеныНоменклатуры.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.Номенклатура = НоменклатураСсылка;
МенеджерЗаписи.ТипЦен = ТипЦенСсылка;
МенеджерЗаписи.Цена = 1500;
МенеджерЗаписи.Записать();
Обязательные к заполнению поля — все измерения регистра, а для периодического — ещё и Период. Ресурсы и реквизиты можно оставить пустыми, если они не отмечены как обязательные. Если пропустить измерение, платформа запишет строку с пустым значением измерения, что часто приводит к «мусорным» записям, которые потом сложно найти.
Для проверки существования записи перед записью используйте тот же менеджер: заполните измерения и вызовите Прочитать(), затем проверьте МенеджерЗаписи.Выбран(). Это позволяет отличить обновление от добавления и, например, не затирать данные, введённые пользователем вручную.
МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ДатаКурса;
МенеджерЗаписи.Валюта = ВалютаСсылка;
МенеджерЗаписи.Прочитать();
Если Не МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Курс = Курс;
МенеджерЗаписи.Записать();
КонецЕсли;Пакетное добавление через набор записей
Когда строк много — например, загрузка тысяч курсов валют из файла — менеджер записи в цикле работает медленно: каждая итерация выполняет отдельную запись в базу. Набор записей позволяет накопить строки в памяти и записать их одной транзакцией, что существенно быстрее и безопаснее.
НаборЗаписей = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Для Каждого СтрокаДанных Из ДанныеИзФайла Цикл
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = СтрокаДанных.Дата;
НоваяЗапись.Валюта = СтрокаДанных.Валюта;
НоваяЗапись.Курс = СтрокаДанных.Курс;
КонецЦикла;
НаборЗаписей.Записать();
Важная особенность: для независимого регистра набор записей без установленного отбора при записи с параметром Записать(Истина) (по умолчанию) полностью заменяет содержимое регистра. Если нужно только добавить строки к существующим, либо записывайте через менеджер записи, либо используйте отбор по измерениям, либо вызывайте Записать(Ложь) — тогда новые строки добавятся к имеющимся, а совпадающие по ключу перезапишутся.
Запись в регистр, подчинённый регистратору
Регистр сведений с режимом «Подчинение регистратору» — это, по сути, движения документа. Каждая строка привязана к документу-регистратору, и удаление документа автоматически удаляет его записи. Записывать такой регистр в обход документа нельзя: платформа выдаст ошибку «Запись регистра, подчинённого регистратору, возможна только с отбором по регистратору».
Типовое место для такого кода — обработчик ОбработкаПроведения модуля объекта документа. Набор записей доступен через коллекцию Движения:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.СтатусыЗаказов.Записывать = Истина;
Движение = Движения.СтатусыЗаказов.Добавить();
Движение.Период = Дата;
Движение.Заказ = ЗаказПокупателя;
Движение.Статус = Перечисления.СтатусыЗаказа.Подтверждён;
КонецПроцедуры;
Если нужно добавить движения в уже существующий документ извне (например, из обработки), получите набор записей, установите отбор по регистратору и запишите:
НаборЗаписей = РегистрыСведений.СтатусыЗаказов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ТекущаяДатаСеанса();
НоваяЗапись.Заказ = ЗаказСсылка;
НоваяЗапись.Статус = Перечисления.СтатусыЗаказа.Отгружен;
НаборЗаписей.Записать();
Учтите: такая запись заменит все прежние движения документа по этому регистру. Если нужно сохранить существующие строки, сначала вызовите НаборЗаписей.Прочитать(), а затем добавляйте новые.
Особенности периодических регистров
В периодическом регистре ключ записи включает поле Период. Платформа автоматически приводит указанную дату к началу периода: при периодичности «в пределах дня» время обрезается, при «в пределах месяца» подставляется первое число. Две записи с датами внутри одного периода и одинаковыми измерениями — это одна и та же запись: вторая перезапишет первую.
Для получения актуального значения используется виртуальная таблица СрезПоследних, для исторического — срез на нужную дату. При программной записи убедитесь, что вы не создаёте запись «в будущем» случайно: срез последних всегда вернёт самую позднюю запись, и ошибочная запись с датой через год станет «текущей» для всех отчётов.
Транзакции и обработка ошибок
При массовой загрузке оборачивайте запись в транзакцию, чтобы частично загруженные данные не остались в базе при сбое. Методы НачатьТранзакцию(), ЗафиксироватьТранзакцию() и ОтменитьТранзакцию() обеспечивают целостность: либо загружено всё, либо ничего.
НачатьТранзакцию();
Попытка
НаборЗаписей.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Загрузка данных",
УровеньЖурналаРегистрации.Ошибка,,,
ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
Для очень больших объёмов имеет смысл разбивать загрузку на порции с фиксацией транзакции каждые несколько тысяч записей: это снижает время блокировки таблицы регистра для других пользователей. Также полезно отключать итоги и использовать НаборЗаписей.ОбменДанными.Загрузка = Истина при чисто технической загрузке — это отключает проверку заполнения и подписки на события, что ускоряет запись, но требует от разработчика гарантии корректности данных.
Как проверить результат записи
После выполнения кода убедитесь, что запись действительно появилась и содержит ожидаемые значения. Самый быстрый способ — открыть регистр в режиме предприятия через список регистра сведений или выполнить запрос в консоли запросов.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ *
|ИЗ РегистрСведений.ЦеныНоменклатуры
|ГДЕ Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
Результат = Запрос.Выполнить().Выгрузить();
Для периодического регистра проверяйте и срез последних: именно его увидят прикладные механизмы. Если запись в регистре есть, но срез возвращает другое значение, значит существует более поздняя запись по тем же измерениям.
Как проверить результат
Строка видна с заполненными измерениями и ресурсами
Строки нет или измерение пустое — проверьте код заполнения
Возвращается добавленное значение
Возвращается старое значение — есть более поздняя запись
Нет ошибок по вашему событию
Есть ошибки транзакции — данные могли не записаться
Частые вопросы
Можно ли добавить запись в регистр сведений из внешней обработки?
Да. Код записи одинаков в модуле документа, общем модуле и внешней обработке. Ограничение одно: для подчинённого регистратору регистра нужен действительный документ-регистратор в отборе набора записей. Для независимого регистра достаточно прав на добавление у текущего пользователя.
Почему Записать() завершается ошибкой «Нарушение прав доступа»?
У пользователя, от имени которого выполняется код, нет права «Добавление» или «Изменение» на этот регистр. Проверьте роли в конфигураторе. Альтернатива — выполнить запись в привилегированном модуле через УстановитьПривилегированныйРежим(Истина), но делайте это осознанно: привилегированный режим обходит все настройки прав.
Как обновить существующую запись, а не создать новую?
В независимом регистре запись однозначно определяется значениями измерений (и периодом). Заполните менеджер записи теми же измерениями и вызовите Записать() — старая строка будет перезаписана. Отдельной команды «обновить» не требуется.
Что делает свойство ОбменДанными.Загрузка и когда его ставить?
При значении Истина платформа пропускает проверку заполнения реквизитов и не вызывает подписки на события записи. Это ускоряет массовую загрузку и предотвращает побочные эффекты, но вся ответственность за корректность данных ложится на ваш код. Для разовой интерактивной записи лучше оставить Ложь.
Как записать несколько тысяч строк, не блокируя работу пользователей?
Используйте набор записей с Записать(Ложь), разбивайте загрузку на порции по несколько тысяч строк с отдельной транзакцией на порцию и по возможности выполняйте загрузку в фоновом задании в нерабочее время. Это сокращает длительность блокировок таблицы регистра.
Почему после записи в периодический регистр дата изменилась?
Платформа приводит период к началу интервала периодичности. При периодичности «в пределах месяца» дата 15.03 станет 01.03. Это нормальное поведение, а не ошибка — учитывайте его при сравнении загруженных данных с источником.
Что важно запомнить
Одиночную запись в независимый регистр добавляйте менеджером записи, массовую загрузку — набором записей с Записать(Ложь), а подчинённый регистратору регистр — только набором с отбором по регистратору. Всегда заполняйте все измерения, проверяйте результат запросом и делайте резервную копию перед массовой загрузкой.