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

· 9 мин

Содержание

Добавить запись в регистр сведений без регистратора можно, только если у регистра в конфигураторе свойство «Режим записи» равно «Независимый». Тогда одна запись создаётся через РегистрыСведений.ИмяРегистра.СоздатьМенеджерЗаписи(), а пачка записей — через СоздатьНаборЗаписей() с отбором. Код выполняется на сервере.

Если регистр подчинён регистратору, записать в него «просто так» нельзя: движения формирует только документ. Главный риск при записи в независимый регистр — набор без отбора: он с замещением стирает весь регистр. Об этом и о периодичности подробнее в разделах про наборы и период.

Независимый регистр и подчинённый: в чём разница при записи

Режим записи задаётся в палитре свойств регистра сведений, свойство «Режим записи». От него зависит, кто и как может создавать записи.

ПризнакНезависимыйПодчинение регистратору
Кто пишетЛюбой код, пользователь в форме спискаТолько документ-регистратор
Менеджер записиЕсть, СоздатьМенеджерЗаписи()Нет
Отбор набораПо периоду и измерениямТолько по регистратору
Ключ записиПериод (если регистр периодический) + измеренияРегистратор + номер строки
Периодичность «В пределах регистратора»НедоступнаДоступна
Ручной ввод в форме спискаДаНет

📌 Что из этого следует на практике:

  • 🔑 В независимом регистре запись уникальна по ключу: период плюс все измерения. Две записи с одинаковым ключом не уживутся.
  • 🧾 В подчинённом регистре уникальность держится на регистраторе. Записи с одинаковыми измерениями от разных документов — нормальная ситуация.
  • 🗑️ При отмене проведения документа его движения в подчинённом регистре удаляются. У независимого регистра такой автоматики нет: что записали — то и лежит, пока код или пользователь не удалит.

Если регистр подчинён, а запись нужна без документа

Вариантов два, и оба требуют работы в конфигураторе:

  1. Завести служебный документ (например, «Корректировка регистра»), который в обработке проведения пишет нужные строки в Движения. Это штатный путь: у каждой записи будет понятный источник.
  2. Перевести регистр в режим «Независимый». Это меняет структуру таблицы и ключ записи, поэтому проверяйте на копии базы и пересматривайте весь код, который пишет в этот регистр через Движения.

Попытка обойти регистратор через набор с пустым отбором по регистратору не даст «записи без документа». Измерение Регистратор у подчинённого регистра обязательно.

Одна запись через менеджер записи

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

Пример: регистр «КонтактныеТелефоны» с измерением Контрагент и ресурсом Телефон, непериодический.

&НаСервереБезКонтекста
Процедура ЗаписатьТелефон(Контрагент, Телефон)

    МенеджерЗаписи = РегистрыСведений.КонтактныеТелефоны.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Контрагент = Контрагент;
    МенеджерЗаписи.Телефон    = Телефон;
    МенеджерЗаписи.Записать(); // Замещать = Истина по умолчанию

КонецПроцедуры

У метода Записать() один параметр — Замещать:

  • ✅ Истина (по умолчанию) — если запись с таким ключом уже есть, она перезаписывается. Новая или старая — неважно, в регистре окажется одна строка.
  • ⛔ Ложь — если запись с таким ключом есть, платформа вызовет исключение. Удобно, когда дубль должен считаться ошибкой, а не тихо затирать старые данные.

Как изменить существующую запись, не потеряв остальные поля

Частая ошибка — создать менеджер, заполнить ключ и один ресурс и вызвать Записать(). Остальные ресурсы и реквизиты при этом станут пустыми: менеджер пишет запись целиком.

Правильный порядок — прочитать, поменять, записать:

МенеджерЗаписи = РегистрыСведений.КонтактныеТелефоны.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Контрагент = Контрагент;
МенеджерЗаписи.Прочитать();

Если МенеджерЗаписи.Выбран() Тогда
    МенеджерЗаписи.Телефон = НовыйТелефон;
    МенеджерЗаписи.Записать();
Иначе
    // записи с таким ключом нет — решаем, создавать ли новую
КонецЕсли;

Прочитать() ищет запись по заполненным ключевым полям. Выбран() возвращает Истина, если запись найдена.

💡 Удаляется запись тем же менеджером: заполните ключ, вызовите Прочитать(), затем Удалить().

Пакетная запись: набор записей с отбором

Когда записей десятки и сотни, менеджер в цикле работает медленно: каждое Записать() — отдельное обращение к базе. Для пакетов есть НаборЗаписей.

Логика набора простая: отбор говорит, какой кусок регистра набор представляет. При записи с замещением платформа удаляет в регистре всё, что попадает под отбор, и пишет содержимое набора.

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

Для Каждого Строка Из ТаблицаЦен Цикл
    Запись = Набор.Добавить();
    Запись.Поставщик   = Поставщик;
    Запись.Номенклатура = Строка.Номенклатура;
    Запись.Цена         = Строка.Цена;
КонецЦикла;

Набор.Записать(); // заменит все цены этого поставщика

Здесь после записи у поставщика останутся только те позиции, что были в ТаблицаЦен. Старые позиции, которых нет в таблице, исчезнут. Если нужно именно так — это правильный код.

Добавить, а не заменить

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

Второй путь — сначала прочитать набор, затем дополнить и записать с замещением:

Набор = РегистрыСведений.ЦеныПоставщиков.СоздатьНаборЗаписей();
Набор.Отбор.Поставщик.Установить(Поставщик);
Набор.Прочитать();

Запись = Набор.Добавить();
Запись.Поставщик    = Поставщик;
Запись.Номенклатура = НоваяНоменклатура;
Запись.Цена         = НоваяЦена;

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

Главная ловушка: набор без отбора

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

Перед любым Набор.Записать() проверьте, что отбор установлен хотя бы по одному полю и значение в нём не пустое. Пустая ссылка в отборе — тоже отбор, но по «пустому» значению, а не по нужному объекту.

💡 Заполняйте в каждой записи набора те же значения измерений, что и в отборе. Запись, которая не соответствует отбору, — источник путаницы и ошибок.

Периодический регистр сведений: период и срез

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

Как это влияет на запись:

  • 📅 Платформа приводит Период к началу интервала периодичности. В регистре с периодичностью «месяц» запись с датой 17.03 сохранится с периодом 01.03.
  • 🔁 Отсюда ловушка: две записи за 5 и 20 марта в «месячном» регистре — это одна и та же запись по ключу. Вторая заменит первую (при замещении) или вызовет ошибку (без него).
  • ⏱️ В регистре «в пределах секунды» записи за один день, но с разным временем — разные записи.

Пример записи курса валюты на дату:

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

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

Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(НачалоДня(ДатаКурса));
Набор.Отбор.Валюта.Установить(Валюта);

Как проверить, что записалось

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

Отбор = Новый Структура("Валюта", Валюта);
Срез = РегистрыСведений.КурсыВалют.СрезПоследних(ДатаКурса, Отбор);

Метод возвращает таблицу значений. Если в ней нет строк — на эту дату и раньше записей нет.

Транзакции, блокировки и обработка исключений

Одна запись менеджером или набором уже выполняется атомарно. Транзакция нужна, когда несколько записей — в разные регистры, или запись в регистр плюс изменение справочника — должны пройти вместе или не пройти вовсе.

Шаблон, который принят в типовых конфигурациях:

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

    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЦеныПоставщиков");
    ЭлементБлокировки.УстановитьЗначение("Поставщик", Поставщик);
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    Блокировка.Заблокировать();

    Набор = РегистрыСведений.ЦеныПоставщиков.СоздатьНаборЗаписей();
    Набор.Отбор.Поставщик.Установить(Поставщик);
    Набор.Прочитать();
    // ... меняем записи ...
    Набор.Записать();

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

Исключение
    ОтменитьТранзакцию();
    ЗаписьЖурналаРегистрации("Загрузка цен поставщиков",
        УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    ВызватьИсключение;
КонецПопытки;

Что здесь важно:

  1. НачатьТранзакцию() стоит до Попытка. Если поставить внутрь, при сбое на старте транзакции блок Исключение попытается отменить то, что не начиналось.
  2. Управляемая блокировка нужна при схеме «прочитать → изменить → записать». Без неё два сеанса прочитают одно и то же, и запись одного из них потеряется. Блокировка работает, если в свойствах конфигурации режим управления блокировкой данных — «Управляемый» или «Автоматический и управляемый».
  3. В блоке Исключение после отмены транзакции ошибку не глотают, а пробрасывают ВызватьИсключение. Иначе вызывающий код решит, что всё записалось.
  4. Блокируйте по тем же полям, что стоят в отборе набора, а не весь регистр. Блокировка всей таблицы останавливает работу других пользователей с этим регистром.

Права и привилегированный режим

Запись выполняется с правами текущего пользователя. Если у роли нет права «Изменение» на регистр, будет ошибка доступа.

Для служебных записей (технические настройки, кэш) на сервере используют УстановитьПривилегированныйРежим(Истина) перед записью. Применяйте точечно: в привилегированном режиме права не проверяются вообще.

Скорость и правила, проверенные на больших загрузках

Когда в регистр сведений надо загрузить десятки тысяч строк (цены, остатки из внешней системы, справочные данные), выбор метода влияет на время в разы.

ЗадачаЧем писатьПочему
Одна запись из формы или обработчикаМенеджерЗаписиПроще читать, есть Прочитать()/Выбран()
Заменить данные по одному объектуНабор с отбором, Записать()Одна операция удаления и вставки
Догрузить новые строкиНабор, Записать(Ложь)Без лишнего удаления
Десятки тысяч строкНабор порциямиКороткие транзакции, меньше блокировок

Практические правила:

  • 📦 Порции. Делите большую загрузку на наборы по 500–5000 записей, по естественному разрезу: поставщик, валюта, месяц. Каждая порция — своя транзакция. Если одна упадёт, остальные сохранятся, а блокировки не будут висеть минутами.
  • 🚫 Не пишите менеджером в цикле тысячи записей. Это тысячи обращений к базе.
  • 🔇 Обработчики набора. Если в модуле набора записей регистра есть ПередЗаписью или ПриЗаписи с тяжёлой логикой, а при загрузке она не нужна, установите Набор.ОбменДанными.Загрузка = Истина. Обработчики будут вызваны, но по соглашению типовых конфигураций они сразу выходят при этом флаге. Проверьте, что в вашем модуле такая проверка есть.
  • 🔍 Не читайте лишнего. Если весь кусок регистра заменяется целиком, Набор.Прочитать() перед записью не нужен.
  • 🧮 Сравнение перед записью. Для регулярной синхронизации прочитайте текущий набор, сравните с новыми данными и пишите только изменившиеся разрезы. Регистр меньше «дёргается», журнал регистрации и обмены не получают лишних изменений.
Какой у вас случай?

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

Можно ли создать менеджер записи на клиенте?
Нет. Регистры и их менеджеры записи доступны в серверном контексте. С клиента вызовите серверную процедуру и передайте в неё значения полей.
Как добавить запись вручную, без кода?
Откройте форму списка регистра: при включённой команде «Все функции» — Все функции → Регистры сведений → имя регистра, кнопка «Создать». Это работает только для независимых регистров и при наличии прав на изменение.
Можно ли записать в регистр сведений запросом?
Нет. Язык запросов 1С только читает данные. Писать нужно объектами: менеджером записи или набором.
Чем отличается ресурс от реквизита независимого регистра при записи?
При записи — ничем, оба заполняются одинаково и в ключ не входят. Разница в смысле: ресурсы — основные значения (их берёт, например, срез последних), реквизиты — дополнительная информация.
Почему после записи пропали другие записи регистра?
Почти всегда это набор с пустым или неверным отбором и запись с замещением. Восстановить можно только из резервной копии, поэтому проверку отбора добавляйте до Записать().