Как добавить запись в регистр сведений без регистратора
Содержание
Добавить запись в регистр сведений
без регистратора можно, только если у регистра в конфигураторе свойство «Режим записи» равно «Независимый». Тогда одна запись создаётся через РегистрыСведений.ИмяРегистра.СоздатьМенеджерЗаписи(), а пачка записей — через СоздатьНаборЗаписей() с отбором. Код выполняется на сервере.
Если регистр подчинён регистратору, записать в него «просто так» нельзя: движения формирует только документ. Главный риск при записи в независимый регистр — набор без отбора: он с замещением стирает весь регистр. Об этом и о периодичности подробнее в разделах про наборы и период.
Независимый регистр и подчинённый: в чём разница при записи
Режим записи задаётся в палитре свойств регистра сведений, свойство «Режим записи». От него зависит, кто и как может создавать записи.
| Признак | Независимый | Подчинение регистратору |
|---|---|---|
| Кто пишет | Любой код, пользователь в форме списка | Только документ-регистратор |
| Менеджер записи | Есть, СоздатьМенеджерЗаписи() | Нет |
| Отбор набора | По периоду и измерениям | Только по регистратору |
| Ключ записи | Период (если регистр периодический) + измерения | Регистратор + номер строки |
| Периодичность «В пределах регистратора» | Недоступна | Доступна |
| Ручной ввод в форме списка | Да | Нет |
📌 Что из этого следует на практике:
- 🔑 В независимом регистре запись уникальна по ключу: период плюс все измерения. Две записи с одинаковым ключом не уживутся.
- 🧾 В подчинённом регистре уникальность держится на регистраторе. Записи с одинаковыми измерениями от разных документов — нормальная ситуация.
- 🗑️ При отмене проведения документа его движения в подчинённом регистре удаляются. У независимого регистра такой автоматики нет: что записали — то и лежит, пока код или пользователь не удалит.
Если регистр подчинён, а запись нужна без документа
Вариантов два, и оба требуют работы в конфигураторе:
- Завести служебный документ (например, «Корректировка регистра»), который в обработке проведения пишет нужные строки в
Движения. Это штатный путь: у каждой записи будет понятный источник. - Перевести регистр в режим «Независимый». Это меняет структуру таблицы и ключ записи, поэтому проверяйте на копии базы и пересматривайте весь код, который пишет в этот регистр через
Движения.
Попытка обойти регистратор через набор с пустым отбором по регистратору не даст «записи без документа». Измерение Регистратор у подчинённого регистра обязательно.
Одна запись через менеджер записи
МенеджерЗаписи — объект для работы ровно с одной записью независимого регистра. Свойства у него те же, что поля регистра: Период (если регистр периодический), все измерения, ресурсы и реквизиты.
Пример: регистр «КонтактныеТелефоны» с измерением Контрагент и ресурсом Телефон, непериодический.
&НаСервереБезКонтекста
Процедура ЗаписатьТелефон(Контрагент, Телефон)
МенеджерЗаписи = РегистрыСведений.КонтактныеТелефоны.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Контрагент = Контрагент;
МенеджерЗаписи.Телефон = Телефон;
МенеджерЗаписи.Записать(); // Замещать = Истина по умолчанию
КонецПроцедуры
У метода Записать() один параметр — Замещать:
- ✅
Истина(по умолчанию) — если запись с таким ключом уже есть, она перезаписывается. Новая или старая — неважно, в регистре окажется одна строка. - ⛔
Ложь— если запись с таким ключом есть, платформа вызовет исключение. Удобно, когда дубль должен считаться ошибкой, а не тихо затирать старые данные.
Как изменить существующую запись, не потеряв остальные поля
Частая ошибка — создать менеджер, заполнить ключ и один ресурс и вызвать Записать(). Остальные ресурсы и реквизиты при этом станут пустыми: менеджер пишет запись целиком.
Правильный порядок — прочитать, поменять, записать:
МенеджерЗаписи = РегистрыСведений.КонтактныеТелефоны.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Контрагент = Контрагент;
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Телефон = НовыйТелефон;
МенеджерЗаписи.Записать();
Иначе
// записи с таким ключом нет — решаем, создавать ли новую
КонецЕсли;
Прочитать() ищет запись по заполненным ключевым полям. Выбран() возвращает Истина, если запись найдена.
💡 Удаляется запись тем же менеджером: заполните ключ, вызовите Прочитать(), затем Удалить().
Пакетная запись: набор записей с отбором
Когда записей десятки и сотни, менеджер в цикле работает медленно: каждое Записать() — отдельное обращение к базе. Для пакетов есть НаборЗаписей.
Логика набора простая: отбор говорит, какой кусок регистра набор представляет. При записи с замещением платформа удаляет в регистре всё, что попадает под отбор, и пишет содержимое набора.
Набор = РегистрыСведений.ЦеныПоставщиков.СоздатьНаборЗаписей();
Набор.Отбор.Поставщик.Установить(Поставщик);
Для Каждого Строка Из ТаблицаЦен Цикл
Запись = Набор.Добавить();
Запись.Поставщик = Поставщик;
Запись.Номенклатура = Строка.Номенклатура;
Запись.Цена = Строка.Цена;
КонецЦикла;
Набор.Записать(); // заменит все цены этого поставщика
Здесь после записи у поставщика останутся только те позиции, что были в ТаблицаЦен. Старые позиции, которых нет в таблице, исчезнут. Если нужно именно так — это правильный код.
Добавить, а не заменить
Чтобы дописать строки к существующим, используйте Набор.Записать(Ложь). Записи с новыми ключами добавятся, но если хоть одна совпадёт по ключу с уже существующей, запись набора упадёт с исключением.
Второй путь — сначала прочитать набор, затем дополнить и записать с замещением:
Набор = РегистрыСведений.ЦеныПоставщиков.СоздатьНаборЗаписей();
Набор.Отбор.Поставщик.Установить(Поставщик);
Набор.Прочитать();
Запись = Набор.Добавить();
Запись.Поставщик = Поставщик;
Запись.Номенклатура = НоваяНоменклатура;
Запись.Цена = НоваяЦена;
Набор.Записать();
Главная ловушка: набор без отбора
Набор без установленного отбора и Записать() с замещением очищают весь регистр, а потом пишут в него только строки набора. Так теряют курсы валют, настройки и цены за годы.
Перед любым Набор.Записать() проверьте, что отбор установлен хотя бы по одному полю и значение в нём не пустое. Пустая ссылка в отборе — тоже отбор, но по «пустому» значению, а не по нужному объекту.
💡 Заполняйте в каждой записи набора те же значения измерений, что и в отборе. Запись, которая не соответствует отбору, — источник путаницы и ошибок.
Периодический регистр сведений: период и срез
У периодического независимого регистра есть поле Период, и оно входит в ключ записи. Периодичность задаётся в свойствах регистра: «В пределах секунды», «дня», «месяца», «квартала», «года».
Как это влияет на запись:
- 📅 Платформа приводит
Периодк началу интервала периодичности. В регистре с периодичностью «месяц» запись с датой 17.03 сохранится с периодом 01.03. - 🔁 Отсюда ловушка: две записи за 5 и 20 марта в «месячном» регистре — это одна и та же запись по ключу. Вторая заменит первую (при замещении) или вызовет ошибку (без него).
- ⏱️ В регистре «в пределах секунды» записи за один день, но с разным временем — разные записи.
Пример записи курса валюты на дату:
МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = НачалоДня(ДатаКурса);
МенеджерЗаписи.Валюта = Валюта;
МенеджерЗаписи.Курс = 92.15;
МенеджерЗаписи.Кратность = 1;
МенеджерЗаписи.Записать();
Для набора по периодическому регистру ставьте отбор и по периоду, и по измерениям. Иначе с замещением сотрёте историю за все даты:
Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(НачалоДня(ДатаКурса));
Набор.Отбор.Валюта.Установить(Валюта);
Как проверить, что записалось
Для периодического регистра актуальное значение на дату получают методом СрезПоследних() менеджера регистра или одноимённой виртуальной таблицей в запросе:
Отбор = Новый Структура("Валюта", Валюта);
Срез = РегистрыСведений.КурсыВалют.СрезПоследних(ДатаКурса, Отбор);
Метод возвращает таблицу значений. Если в ней нет строк — на эту дату и раньше записей нет.
Транзакции, блокировки и обработка исключений
Одна запись менеджером или набором уже выполняется атомарно. Транзакция нужна, когда несколько записей — в разные регистры, или запись в регистр плюс изменение справочника — должны пройти вместе или не пройти вовсе.
Шаблон, который принят в типовых конфигурациях:
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЦеныПоставщиков");
ЭлементБлокировки.УстановитьЗначение("Поставщик", Поставщик);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Набор = РегистрыСведений.ЦеныПоставщиков.СоздатьНаборЗаписей();
Набор.Отбор.Поставщик.Установить(Поставщик);
Набор.Прочитать();
// ... меняем записи ...
Набор.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Загрузка цен поставщиков",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
Что здесь важно:
НачатьТранзакцию()стоит доПопытка. Если поставить внутрь, при сбое на старте транзакции блокИсключениепопытается отменить то, что не начиналось.- Управляемая блокировка нужна при схеме «прочитать → изменить → записать». Без неё два сеанса прочитают одно и то же, и запись одного из них потеряется. Блокировка работает, если в свойствах конфигурации режим управления блокировкой данных — «Управляемый» или «Автоматический и управляемый».
- В блоке
Исключениепосле отмены транзакции ошибку не глотают, а пробрасываютВызватьИсключение. Иначе вызывающий код решит, что всё записалось. - Блокируйте по тем же полям, что стоят в отборе набора, а не весь регистр. Блокировка всей таблицы останавливает работу других пользователей с этим регистром.
Права и привилегированный режим
Запись выполняется с правами текущего пользователя. Если у роли нет права «Изменение» на регистр, будет ошибка доступа.
Для служебных записей (технические настройки, кэш) на сервере используют УстановитьПривилегированныйРежим(Истина) перед записью. Применяйте точечно: в привилегированном режиме права не проверяются вообще.
Скорость и правила, проверенные на больших загрузках
Когда в регистр сведений надо загрузить десятки тысяч строк (цены, остатки из внешней системы, справочные данные), выбор метода влияет на время в разы.
| Задача | Чем писать | Почему |
|---|---|---|
| Одна запись из формы или обработчика | МенеджерЗаписи | Проще читать, есть Прочитать()/Выбран() |
| Заменить данные по одному объекту | Набор с отбором, Записать() | Одна операция удаления и вставки |
| Догрузить новые строки | Набор, Записать(Ложь) | Без лишнего удаления |
| Десятки тысяч строк | Набор порциями | Короткие транзакции, меньше блокировок |
Практические правила:
- 📦 Порции. Делите большую загрузку на наборы по 500–5000 записей, по естественному разрезу: поставщик, валюта, месяц. Каждая порция — своя транзакция. Если одна упадёт, остальные сохранятся, а блокировки не будут висеть минутами.
- 🚫 Не пишите менеджером в цикле тысячи записей. Это тысячи обращений к базе.
- 🔇 Обработчики набора. Если в модуле набора записей регистра есть
ПередЗаписьюилиПриЗаписис тяжёлой логикой, а при загрузке она не нужна, установитеНабор.ОбменДанными.Загрузка = Истина. Обработчики будут вызваны, но по соглашению типовых конфигураций они сразу выходят при этом флаге. Проверьте, что в вашем модуле такая проверка есть. - 🔍 Не читайте лишнего. Если весь кусок регистра заменяется целиком,
Набор.Прочитать()перед записью не нужен. - 🧮 Сравнение перед записью. Для регулярной синхронизации прочитайте текущий набор, сравните с новыми данными и пишите только изменившиеся разрезы. Регистр меньше «дёргается», журнал регистрации и обмены не получают лишних изменений.
Частые вопросы
Можно ли создать менеджер записи на клиенте?
Как добавить запись вручную, без кода?
Все функции → Регистры сведений → имя регистра, кнопка «Создать». Это работает только для независимых регистров и при наличии прав на изменение.Можно ли записать в регистр сведений запросом?
Чем отличается ресурс от реквизита независимого регистра при записи?
Почему после записи пропали другие записи регистра?
Записать().