Набор записей в 1С: создание, отбор и запись в базу
Содержание
Набор записей создают методом СоздатьНаборЗаписей() у менеджера нужного регистра: например, РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей(). Дальше ставят отбор, читают данные методом Прочитать(), меняют или добавляют строки и сохраняют всё вызовом Записать(). Ниже — каждый шаг с кодом на встроенном языке 1С 8.3.
Набор работает не с объектами ссылочных типов (документами, справочниками), а с записями регистров — сведений, накопления, бухгалтерии и расчёта. Это основной способ программно читать и править содержимое регистра из модуля документа, обработки или общего модуля.
Для каких объектов существует набор записей
Набор записей — это коллекция строк одного регистра, объединённых общим отбором. У каждого вида регистра свой менеджер и свой набор:
- 📊 Регистр сведений
—
РегистрыСведений.ИмяРегистра - 📈 Регистр накопления —
РегистрыНакопления.ИмяРегистра - 📒 Регистр бухгалтерии
—
РегистрыБухгалтерии.ИмяРегистра - 🧮 Регистр расчёта —
РегистрыРасчета.ИмяРегистра
У справочников и документов наборов записей нет — там работают с объектом по ссылке. Набор нужен именно для регистров, потому что регистр хранит множество однотипных строк, а не один объект. Через набор удобно и прочитать текущее состояние регистра, и полностью переписать его часть одной операцией — именно это отличает его от построчной работы с данными.
Важно различать два режима регистра сведений. Подчинённый регистратору регистр привязан к документу-регистратору: его строки пишутся при проведении документа. Независимый регистр не связан с документом, строки в него заносят вручную или кодом. От этого зависит, по какому полю вы будете ставить отбор.
Набор записей устроен одинаково для всех видов регистров, но состав полей в строках разный. У регистра накопления у строки есть вид движения (приход или расход для регистра остатков). У регистра бухгалтерии в строке присутствуют счета дебета и кредита, субконто и признак активности проводки. У регистра расчёта различают период регистрации и период действия. Это влияет на то, какие реквизиты вы заполняете перед записью.
Как создать набор записей в коде
Сам набор создаётся одной строкой — обращением к менеджеру регистра:
НаборЗаписей = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Для регистра накопления или бухгалтерии всё аналогично, меняется только тип менеджера:
НаборНакопления = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборПроводок = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
На этом этапе набор пустой: ни записей из базы, ни отбора в нём ещё нет. Чтобы работать с конкретными строками регистра, сначала задают отбор, а затем читают данные.
Если вам нужна ровно одна запись независимого регистра сведений, набор можно не создавать — быстрее и нагляднее менеджер записи СоздатьМенеджерЗаписи(). О разнице — в разделе про частые вопросы.
Тот же набор записей доступен и при проведении документа — через коллекцию Движения. В обработчике ОбработкаПроведения обращение Движения.ТоварыНаСкладах возвращает набор записей этого регистра, уже привязанный к текущему документу-регистратору. Отбор по регистратору платформа ставит сама, вам остаётся заполнить строки:
Движения.ТоварыНаСкладах.Записывать = Истина;
Строка = Движения.ТоварыНаСкладах.Добавить();
Строка.ВидДвижения = ВидДвиженияНакопления.Приход;
Строка.Период = Дата;
Строка.Номенклатура = ТекущаяСтрока.Номенклатура;
Строка.Количество = ТекущаяСтрока.Количество;
Флаг Записывать = Истина говорит платформе сохранить набор в конце проведения — отдельный вызов Записать() здесь не нужен.
Отбор: как ограничить набор нужными строками
Отбор задаёт, какие именно строки регистра попадут в набор при чтении и какие будут перезаписаны при сохранении. Доступные поля отбора зависят от структуры регистра.
Для регистра, подчинённого регистратору, отбор ставят по документу-регистратору:
НаборНакопления.Отбор.Регистратор.Установить(ДокументСсылка);
НаборНакопления.Прочитать();
Для независимого регистра сведений отбор ставят по его измерениям и периоду:
НаборЗаписей.Отбор.Валюта.Установить(СсылкаНаВалюту);
НаборЗаписей.Отбор.Период.Установить(Дата(2026, 1, 1));
НаборЗаписей.Прочитать();
Метод Установить(Значение) одновременно записывает значение в отбор и включает его использование. Если нужно только включить или выключить проверку поля, работают со свойствами Значение и Использование напрямую. Отбор набора записей поддерживает лишь сравнение на равенство — диапазонов и списков значений в нём нет.
Отбор управляет не только чтением, но и удалением. Если оставить отбор пустым и вызвать Записать(), 1С заместит все строки регистра. Всегда ставьте отбор перед записью.
Чтение, добавление и изменение строк
После Прочитать() набор заполняется строками из базы — их видно через Количество() и обход циклом. Каждая строка — это запись с полями регистра (измерения, ресурсы, реквизиты).
Метод Количество() возвращает число строк в наборе после чтения; до вызова Прочитать() он равен нулю, даже если в регистре данные есть. Обратиться к конкретной строке можно по индексу — НаборЗаписей[0] для первой, индексация идёт с нуля.
Изменить значения в прочитанных строках:
Для Каждого Запись Из НаборЗаписей Цикл
Запись.Курс = Запись.Курс * 1.1;
КонецЦикла;
Добавить новую строку методом Добавить() — он возвращает пустую запись, поля которой вы заполняете:
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Валюта = СсылкаНаВалюту;
НоваяЗапись.Курс = 95;
НоваяЗапись.Кратность = 1;
Очистить набор в памяти — Очистить(). Это не трогает базу: удаление произойдёт только при записи. Такой приём используют, чтобы стереть все строки по отбору: прочитали, очистили, записали — строки по этому отбору исчезнут.
Пока набор не записан, все изменения живут только в оперативной памяти. База обновляется единственным вызовом — Записать().
Запись набора в базу: замещение или добавление
У метода Записать() есть параметр Замещение. Он определяет, что произойдёт со старыми строками регистра по текущему отбору:
| Вызов | Что делает |
|---|---|
Записать() или Записать(Истина) | Замещает: удаляет все строки по отбору и пишет содержимое набора |
Записать(Ложь) | Добавляет строки набора к уже существующим |
По умолчанию замещение включено. Это безопасно для записи от имени регистратора: при повторном проведении документа его старые движения стираются и пишутся заново. Но для независимого регистра с пустым отбором замещение сотрёт весь регистр — об этом предупреждали выше.
Простейший полный цикл записи выглядит так:
НаборЗаписей = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Валюта.Установить(СсылкаНаВалюту);
НаборЗаписей.Отбор.Период.Установить(Дата(2026, 1, 1));
Запись = НаборЗаписей.Добавить();
Запись.Период = Дата(2026, 1, 1);
Запись.Валюта = СсылкаНаВалюту;
Запись.Курс = 95;
Запись.Кратность = 1;
НаборЗаписей.Записать();
При записи регистр отрабатывает свои обработчики и контроль. Если данные грузятся из обмена и бизнес-логику регистра надо пропустить, перед записью ставят флаг загрузки:
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();
Флаг ОбменДанными.Загрузка = Истина отключает проверки и часть обработчиков регистра. Применяйте его только при переносе данных и начальной загрузке, не в обычной работе — иначе в регистр попадут непроверенные строки.
Иногда в обработчики регистра нужно передать дополнительный контекст — например, признак, что запись идёт из конкретной обработки, а не из документа. Для этого служит коллекция ДополнительныеСвойства набора: значения, которые вы в неё положите, доступны в модуле набора записей при записи, но в базе не сохраняются. Это удобный способ управлять логикой записи, не добавляя в регистр лишних реквизитов.
Производительность на больших объёмах
Набор записей читает все строки по отбору в память целиком. Для десятка строк это незаметно, для десятков тысяч — опасно: память и время растут линейно. Несколько приёмов держат нагрузку под контролем.
- Не читайте набором то, что нужно только посчитать. Для анализа и агрегатов используйте запрос к регистру — он не тянет строки в память объектами.
- Пишите замещением, а не по одной строке. Один
Записать(Истина)с готовым набором быстрее, чем чтение, правка и запись в цикле по каждой записи. - Оборачивайте массовую запись в явную транзакцию. Запись одного набора уже идёт в неявной транзакции; когда наборов много, объедините их
НачатьТранзакцию()/ЗафиксироватьТранзакцию()— так меньше накладных расходов и записи согласованы. - Помните про итоги регистра накопления. Каждая запись в регистр накопления пересчитывает итоги. При загрузке больших объёмов это главный источник тормозов — грузите данные порциями и в непиковое время.
- Читайте порциями, а не весь регистр разом. Если набор всё же нужен, ограничивайте отбор узким диапазоном (один регистратор, один период, одно измерение) и обрабатывайте данные частями. Набор без отбора на миллионном регистре попытается поднять в память всё и упрётся в ограничения сервера.
Для управляемых блокировок при конкурентной записи используйте объект БлокировкаДанных до вызова Записать() — это надёжнее, чем полагаться на автоматические блокировки.
Частые ошибки при работе с наборами записей
Большинство проблем с наборами сводится к забытому отбору и неверному режиму замещения. Ниже — как распознать симптом и что проверить.
Записать() стирает весь регистр. Поставьте отбор по регистратору или измерениям до записи.Использование поля отбора не включено. Проверьте значение и то, что отбор реально применился.Записать(). Метод Добавить() меняет только набор в памяти; без записи база не обновится.Записать(Ложь) — режим добавления. Для обновления по отбору нужен режим замещения: Записать() или Записать(Истина).Пример: заполнение регистра сведений из обработки
Разберём типовую задачу — обработка загружает курсы валют и обновляет независимый регистр сведений. Отбор ставим по валюте и периоду, старое значение за эту дату замещаем новым:
Процедура ЗагрузитьКурс(Валюта, ПериодКурса, ЗначениеКурса) Экспорт
Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Валюта.Установить(Валюта);
Набор.Отбор.Период.Установить(ПериодКурса);
Запись = Набор.Добавить();
Запись.Период = ПериодКурса;
Запись.Валюта = Валюта;
Запись.Курс = ЗначениеКурса;
Запись.Кратность = 1;
Набор.Записать();
КонецПроцедуры
Благодаря отбору по валюте и периоду запись затронет только одну комбинацию: курс именно этой валюты на эту дату. Остальные строки регистра не пострадают, потому что замещение работает строго в границах отбора.
Если курсов много и они приходят пачкой, вызывать процедуру в цикле неэффективно — лучше собрать все строки в один набор и записать его целиком. Тогда отбор ставят шире (например, только по периоду), а строки добавляют по всем валютам сразу:
Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(ПериодКурса);
Для Каждого СтрокаКурса Из ТаблицаКурсов Цикл
Запись = Набор.Добавить();
Запись.Период = ПериодКурса;
Запись.Валюта = СтрокаКурса.Валюта;
Запись.Курс = СтрокаКурса.Курс;
Запись.Кратность = 1;
КонецЦикла;
Набор.Записать();
Здесь отбор стоит только по периоду, поэтому одно замещение перепишет курсы всех валют на эту дату сразу. Такой подход на порядок быстрее, чем отдельная запись по каждой валюте: платформа один раз удаляет старые строки по отбору и один раз пишет новые. Главное, чтобы таблица содержала полный набор курсов за период — иначе отсутствующие в таблице валюты за эту дату будут стёрты.
Частые вопросы
Чем набор записей отличается от менеджера записи?
СоздатьМенеджерЗаписи()) работает с одной записью независимого регистра сведений — удобнее, когда нужно прочитать или записать ровно одну строку по ключу.Почему нельзя изменить одну строку, не перезаписывая весь набор?
Записать() старые строки по отбору удаляются и заменяются содержимым набора. Чтобы изменить единственную запись независимого регистра, используйте менеджер записи.Как удалить все строки регистра по регистратору?
Отбор.Регистратор.Установить(Ссылка), вызовите Очистить() и затем Записать(). Пустой набор с замещением удалит все строки по этому регистратору.