Запись и заполнение регистра сведений в 1С 8.3

· 9 мин

Содержание

Регистр сведений заполняется двумя путями: либо кодом напрямую — через менеджер записи или набор записей, либо движениями документа при проведении. Какой путь доступен — решает один переключатель в свойствах регистра: Режим записи. Если стоит Независимый — пишем из кода; если Подчинение регистратору — только через проведение.

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

Измерения, ресурсы и реквизиты: из чего собирается запись

Запись регистра сведений — это строка таблицы, у которой поля делятся на три группы:

  • 🔑 Измерения — ключевые поля. Их комбинация (плюс период для периодического регистра) определяет уникальность записи. Пример: в регистре курсов валют измерение одно — Валюта.
  • 📊 Ресурсы — хранимые значения. То, ради чего регистр существует: Курс, Кратность, Цена, Процент.
  • 📝 Реквизиты — дополнительная информация, которая не входит в ключ и не участвует в уникальности. Например, комментарий или документ-основание.

У периодического регистра добавляется служебное поле Период. Оно входит в ключ наравне с измерениями: по одной и той же валюте можно хранить курс на каждую дату.

Правило: в одном регистре не может быть двух записей с одинаковым набором измерений и периодом. Платформа контролирует это сама и при нарушении выдаёт ошибку записи.

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

Два решения на этапе проектирования, которые потом тяжело переигрывать:

  • Измерение или реквизит. В измерение выносят то, по чему вы будете отбирать и строить срезы. Если поле нужно только «для справки» и по нему не ищут — это реквизит. Лишнее измерение раздувает ключ и замедляет запись.
  • Индексирование. У измерения есть свойство Индексировать. Ставьте индекс тем полям, по которым пойдут отборы в запросах и срезах, — без индекса выборка по большому регистру будет медленной. Но каждый индекс замедляет запись, поэтому индексировать всё подряд не стоит.

Тип ресурса может быть любым, включая составной. На практике в ресурсах держат числа, даты и ссылки; строки большой длины лучше хранить в реквизитах, а не в ключевых полях.

Периодичность и режим записи: что они меняют

Два свойства регистра определяют всю механику заполнения.

Периодичность задаёт, с какой точностью хранится история:

ПериодичностьЧто означает
НепериодическийИстории нет, по ключу — одно значение
В пределах секундыЗапись на каждую секунду
В пределах дняОдна запись на дату
В пределах месяца / квартала / годаЗначение привязано к началу периода
По позиции регистратораПорядок задаёт документ-регистратор

Выбранная периодичность округляет поле Период при записи. Если регистр периодичен «в пределах дня», а вы запишете 01.03.2025 14:30:00, платформа сохранит 01.03.2025 00:00:00.

Режим записи определяет, кто имеет право писать:

  • Независимый — регистр не подчинён документу. Пишем из любого кода: менеджером записи или набором записей.
  • Подчинение регистратору — записи создаются только при проведении документа-регистратора. Напрямую менеджером записи такой регистр не заполнить.

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

Запись из кода: менеджер записи и набор записей

Для независимого регистра есть два объекта.

Менеджер записи — одна запись по полному ключу

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

Запись = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
Запись.Период    = Дата;
Запись.Валюта    = Валюта;
Запись.Курс      = 75.5;
Запись.Кратность = 1;
Запись.Записать(Истина); // Истина — замещать существующую запись

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

  • Записать(Истина) — если запись с таким ключом есть, она перезапишется.
  • Записать(Ложь) — если запись уже существует, платформа выдаст ошибку.

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

Набор записей — несколько записей с общим отбором

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

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

НоваяСтрока = Набор.Добавить();
НоваяСтрока.Период    = Дата;
НоваяСтрока.Валюта    = Валюта;
НоваяСтрока.Курс      = 75.5;
НоваяСтрока.Кратность = 1;

Набор.Записать(Истина); // Истина — заместить все записи по отбору

Ключевой момент — что делает Записать(Замещать) для набора:

  • Записать(Истина) — платформа удалит ВСЕ записи, попадающие под отбор, и запишет вместо них содержимое набора. Если набор пустой, записи по отбору просто удалятся.
  • Записать(Ложь) — записи набора добавятся к уже существующим.

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

Какой объект когда брать:

Что записываем в независимый регистр?

Массовая загрузка: наборы записей и транзакции

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

Соберите один набор на весь массив и запишите его разом:

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

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

Набор.Записать(Ложь); // Ложь — добавить к существующим

Несколько практических приёмов для загрузки:

  1. ⚡ Если грузите частями в цикле, оборачивайте запись в транзакцию НачатьТранзакцию() / ЗафиксироватьТранзакцию() — так платформа не будет открывать её на каждый Записать().
  2. 🧩 При замещении (Записать(Истина)) следите, что отбор охватывает ровно то, что хотите перезаписать. Отбор по одному измерению при нескольких — опасен.
  3. 🔁 Для обновления справочных данных (курсы, прайс) удобнее сначала собрать весь новый набор, потом записать с замещением по периоду — так старые значения не задвоятся.

Когда у регистра несколько измерений, а отбор удобно задать не по всем, в наборе можно явно установить отбор по части измерений. Платформа заместит только записи, попадающие под этот отбор.

Заполнение движениями при проведении документа

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

В модуле документа, в процедуре ОбработкаПроведения:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    Движения.ЦеныНоменклатуры.Записывать = Истина;

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

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

Два обязательных условия, без которых движения не попадут в базу:

  • 🟢 Движения.<ИмяРегистра>.Записывать = Истина — флаг, что набор надо сохранить. Забыли флаг — строки добавили, а в регистре пусто.
  • 🟢 Запись набора происходит автоматически при завершении проведения, если флаг установлен. Вручную Записать() в обработчике вызывать не нужно.

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

Отмена проведения (ОбработкаУдаленияПроведения или перепроведение) сама удаляет старые движения документа — заботиться об очистке в большинстве случаев не нужно.

Чтение: срезы, получение последнего значения и запросы

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

Получить значение на дату (периодический регистр) — метод ПолучитьПоследнее:

Отбор = Новый Структура("Валюта", Валюта);
Данные = РегистрыСведений.КурсыВалют.ПолучитьПоследнее(Дата, Отбор);
Если Данные <> Неопределено Тогда
    Курс = Данные.Курс;
КонецЕсли;

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

Получить одну запись непериодического регистра — метод Получить:

Отбор = Новый Структура("Пользователь", ТекущийПользователь);
Значение = РегистрыСведений.НастройкиПользователей.Получить(Отбор);

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

ВЫБРАТЬ
    КурсыВалют.Валюта,
    КурсыВалют.Курс,
    КурсыВалют.Кратность
ИЗ
    РегистрСведений.КурсыВалют.СрезПоследних(&Дата, Валюта В (&СписокВалют)) КАК КурсыВалют

Первый параметр виртуальной таблицы — дата среза, второй — условие отбора. Если дату не указать, срез берётся на текущий момент.

Чтобы пройти записи построчно в коде, используйте Выбрать():

Выборка = РегистрыСведений.КурсыВалют.Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(Строка(Выборка.Валюта) + ": " + Формат(Выборка.Курс, "ЧГ=0"));
КонецЦикла;

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

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

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

Частые ошибки при записи регистра сведений

Ошибки, на которые уходит больше всего времени у начинающих.

Диагностика: выберите симптом

Ещё две вещи, которые путают:

  • Поле Активность у движений (есть у подчинённых регистратору) — если снять, запись физически остаётся, но не участвует в срезах и итогах. Используется для сторнирования, а не для удаления.
  • Запись в набор идёт в оперативную память до вызова Записать(). Пока метод не вызван, в базе изменений нет — поэтому чтение из другого места их не увидит.

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

Чем менеджер записи отличается от набора записей?
Менеджер записи работает с одной записью по полному ключу измерений и требует ведущего измерения. Набор записей оперирует группой строк по отбору и умеет замещать или удалять их пачкой. Для массовых операций берут набор.
Можно ли заполнить подчинённый регистратору регистр из внешней обработки?
Напрямую — нет. Такой регистр пишется только при проведении документа-регистратора. Если нужна запись из кода, измените режим на «Независимый» в конфигураторе (с осторожностью — это меняет логику учёта).
Что произойдёт, если записать пустой набор с замещением?
Все записи, попадающие под установленный отбор, будут удалены. Это штатный способ очистить группу записей регистра по условию.
Как обновить одно значение, не затронув остальные?
Для набора установите отбор по полному ключу (все измерения) и запишите с замещением — заместится только эта запись. Либо используйте менеджер записи: прочитать, изменить ресурс, записать.
Чем срез последних отличается от метода ПолучитьПоследнее?
Срез последних — виртуальная таблица в запросе, возвращает последние записи сразу по множеству ключей на дату. ПолучитьПоследнее отдаёт одну запись по конкретному отбору. Для выборок и отчётов эффективнее срез.