Набор записей в 1С: создание, отбор и запись в базу

· 9 мин

Содержание

Набор записей создают методом СоздатьНаборЗаписей() у менеджера нужного регистра: например, РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей(). Дальше ставят отбор, читают данные методом Прочитать(), меняют или добавляют строки и сохраняют всё вызовом Записать(). Ниже — каждый шаг с кодом на встроенном языке 1С 8.3.

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

Для каких объектов существует набор записей

Набор записей — это коллекция строк одного регистра, объединённых общим отбором. У каждого вида регистра свой менеджер и свой набор:

  • 📊 Регистр сведений — РегистрыСведений.ИмяРегистра
  • 📈 Регистр накопления — РегистрыНакопления.ИмяРегистра
  • 📒 Регистр бухгалтерии — РегистрыБухгалтерии.ИмяРегистра
  • 🧮 Регистр расчёта — РегистрыРасчета.ИмяРегистра

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

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

Набор записей устроен одинаково для всех видов регистров, но состав полей в строках разный. У регистра накопления у строки есть вид движения (приход или расход для регистра остатков). У регистра бухгалтерии в строке присутствуют счета дебета и кредита, субконто и признак активности проводки. У регистра расчёта различают период регистрации и период действия. Это влияет на то, какие реквизиты вы заполняете перед записью.

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

Сам набор создаётся одной строкой — обращением к менеджеру регистра:

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

Для регистра накопления или бухгалтерии всё аналогично, меняется только тип менеджера:

НаборНакопления = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборПроводок   = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();

На этом этапе набор пустой: ни записей из базы, ни отбора в нём ещё нет. Чтобы работать с конкретными строками регистра, сначала задают отбор, а затем читают данные.

Если вам нужна ровно одна запись независимого регистра сведений, набор можно не создавать — быстрее и нагляднее менеджер записи СоздатьМенеджерЗаписи(). О разнице — в разделе про частые вопросы.

Тот же набор записей доступен и при проведении документа — через коллекцию Движения. В обработчике ОбработкаПроведения обращение Движения.ТоварыНаСкладах возвращает набор записей этого регистра, уже привязанный к текущему документу-регистратору. Отбор по регистратору платформа ставит сама, вам остаётся заполнить строки:

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

Флаг Записывать = Истина говорит платформе сохранить набор в конце проведения — отдельный вызов Записать() здесь не нужен.

Отбор: как ограничить набор нужными строками

Отбор задаёт, какие именно строки регистра попадут в набор при чтении и какие будут перезаписаны при сохранении. Доступные поля отбора зависят от структуры регистра.

Для регистра, подчинённого регистратору, отбор ставят по документу-регистратору:

НаборНакопления.Отбор.Регистратор.Установить(ДокументСсылка);
НаборНакопления.Прочитать();

Для независимого регистра сведений отбор ставят по его измерениям и периоду:

НаборЗаписей.Отбор.Валюта.Установить(СсылкаНаВалюту);
НаборЗаписей.Отбор.Период.Установить(Дата(2026, 1, 1));
НаборЗаписей.Прочитать();

Метод Установить(Значение) одновременно записывает значение в отбор и включает его использование. Если нужно только включить или выключить проверку поля, работают со свойствами Значение и Использование напрямую. Отбор набора записей поддерживает лишь сравнение на равенство — диапазонов и списков значений в нём нет.

Отбор управляет не только чтением, но и удалением. Если оставить отбор пустым и вызвать Записать(), 1С заместит все строки регистра. Всегда ставьте отбор перед записью.

Чтение, добавление и изменение строк

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

Метод Количество() возвращает число строк в наборе после чтения; до вызова Прочитать() он равен нулю, даже если в регистре данные есть. Обратиться к конкретной строке можно по индексу — НаборЗаписей[0] для первой, индексация идёт с нуля.

Изменить значения в прочитанных строках:

Для Каждого Запись Из НаборЗаписей Цикл
    Запись.Курс = Запись.Курс * 1.1;
КонецЦикла;

Добавить новую строку методом Добавить() — он возвращает пустую запись, поля которой вы заполняете:

НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Валюта = СсылкаНаВалюту;
НоваяЗапись.Курс = 95;
НоваяЗапись.Кратность = 1;

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

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

Запись набора в базу: замещение или добавление

У метода Записать() есть параметр Замещение. Он определяет, что произойдёт со старыми строками регистра по текущему отбору:

ВызовЧто делает
Записать() или Записать(Истина)Замещает: удаляет все строки по отбору и пишет содержимое набора
Записать(Ложь)Добавляет строки набора к уже существующим

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

Простейший полный цикл записи выглядит так:

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

Запись = НаборЗаписей.Добавить();
Запись.Период = Дата(2026, 1, 1);
Запись.Валюта = СсылкаНаВалюту;
Запись.Курс = 95;
Запись.Кратность = 1;

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

При записи регистр отрабатывает свои обработчики и контроль. Если данные грузятся из обмена и бизнес-логику регистра надо пропустить, перед записью ставят флаг загрузки:

НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();

Флаг ОбменДанными.Загрузка = Истина отключает проверки и часть обработчиков регистра. Применяйте его только при переносе данных и начальной загрузке, не в обычной работе — иначе в регистр попадут непроверенные строки.

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

Производительность на больших объёмах

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

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

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

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

Большинство проблем с наборами сводится к забытому отбору и неверному режиму замещения. Ниже — как распознать симптом и что проверить.

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

Пример: заполнение регистра сведений из обработки

Разберём типовую задачу — обработка загружает курсы валют и обновляет независимый регистр сведений. Отбор ставим по валюте и периоду, старое значение за эту дату замещаем новым:

Процедура ЗагрузитьКурс(Валюта, ПериодКурса, ЗначениеКурса) Экспорт

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

    Запись = Набор.Добавить();
    Запись.Период = ПериодКурса;
    Запись.Валюта = Валюта;
    Запись.Курс = ЗначениеКурса;
    Запись.Кратность = 1;

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

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

Благодаря отбору по валюте и периоду запись затронет только одну комбинацию: курс именно этой валюты на эту дату. Остальные строки регистра не пострадают, потому что замещение работает строго в границах отбора.

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

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

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

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

Здесь отбор стоит только по периоду, поэтому одно замещение перепишет курсы всех валют на эту дату сразу. Такой подход на порядок быстрее, чем отдельная запись по каждой валюте: платформа один раз удаляет старые строки по отбору и один раз пишет новые. Главное, чтобы таблица содержала полный набор курсов за период — иначе отсутствующие в таблице валюты за эту дату будут стёрты.

Проверка перед записью набора
Выполнено: 0 / 5

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

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