Ошибка «Период не может быть пустым» при записи в регистр сведений: причины и решение

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

При программной работе с регистрами сведений в 1С разработчики часто сталкиваются с ошибкой: «Ошибка при записи в регистр сведений (Период не может быть пустым!)». Эта ситуация типична для периодических регистров, где дата (период) является частью уникального ключа записи. Чтобы вовремя выявлять подобные проблемы в коде, рекомендуется регулярно проводить анализ конфигураций и расширений на наличие ошибок. Давайте подробно разберем, почему возникает эта ошибка, даже если нам кажется, что данные корректны, и как правильно написать код для изменения записей.

Анализ исходной проблемы

Рассмотрим ситуацию, с которой столкнулся автор темы. Имеется задача: получить данные из среза последних и на их основании создать новые записи (или обновить существующие) в регистре сведений УсловияЗакрепленияТС. Подобный разбор часто встречается, когда проводится качественный Code-review чужих разработок.

Изначальный код выглядел следующим образом:


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

При выполнении этого кода платформа выдает ошибку о незаполненном периоде. Давайте выясним причину. Метод СоздатьМенеджерЗаписи() создает в оперативной памяти пустой объект. Это "чистый лист". Он не знает о том, что происходит в вашем запросе, и не копирует автоматически данные из выборки.

В периодическом регистре сведений уникальность записи определяется набором: Период + Измерения. Если вы не укажете Период, система управления базами данных (СУБД) не сможет сохранить запись, так как это поле не допускает значений NULL.

Основные ошибки в коде

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

  1. Отсутствие присвоения Периода. Свойство Период у созданного объекта менеджера записи осталось пустым (дата 01.01.0001), что недопустимо для записи, если не задана конкретная логика.
  2. Отсутствие заполнения Измерений. В коде заполняется только ресурс НормаЗаМесяц. Измерение ТС (Транспортное Средство), которое есть в выборке запроса, не передается в менеджер записи. Запись в регистр без измерений бессмысленна и часто невозможна.
  3. Некорректное именование переменных. Переменная названа НаборЗаписей, хотя по факту в ней хранится МенеджерЗаписи. Это нарушает стандарты и методики разработки конфигураций 1С и вводит в заблуждение при чтении кода, так как методы работы с наборами и менеджерами отличаются.

Правильное решение задачи

Чтобы исправить ошибку, нам необходимо явно указать все ключевые поля перед вызовом метода Записать(). Исправим код шаг за шагом.

Во-первых, переименуем переменную для ясности. Во-вторых, добавим заполнение периода и измерения ТС. В зависимости от задачи, Период может браться из текущей даты или из данных запроса.

Вот исправленный и рабочий вариант кода:


Для Каждого ТекСтр из РезультатЗапроса Цикл
    // Создаем новый объект МенеджерЗаписи
    МенеджерЗаписи = РегистрыСведений.УсловияЗакрепленияТС.СоздатьМенеджерЗаписи();
    
    // 1. Заполняем Измерения (обязательно для идентификации записи)
    МенеджерЗаписи.ТС = ТекСтр.ТС;
    
    // 2. Заполняем Период (обязательно для периодических регистров)
    // Вариант А: Если нужно создать запись на текущий момент
    МенеджерЗаписи.Период = ТекущаяДата(); 
    
    // Вариант Б: Если период нужно взять из источника (если он был в запросе)
    // МенеджерЗаписи.Период = ТекСтр.Период; 
    
    // 3. Заполняем Ресурсы
    МенеджерЗаписи.НормаЗаМесяц = ТекСтр.ДанныеТекМесяца;
    
    // Записываем данные в базу
    МенеджерЗаписи.Записать();
КонецЦикла;

Различие между Менеджером записи и Набором записей

В обсуждении справедливо заметили нюанс использования терминологии. Давайте разберем разницу, так как это влияет на производительность.

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

Набор записей (RecordSet) позволяет записывать данные "пакетами". Если вам нужно перезаписать данные за определенный период или по определенному отбору (например, по конкретному ТС), использование набора записей будет более оптимальным.

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


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

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

// Одна запись в базу данных сразу для всех строк
Набор.Записать(); 

Почему возникает путаница с "Проверкой заполнения"?

Часто возникает вопрос: почему свойство метаданных "Проверка заполнения" (Выдавать ошибку) работает в формах, но кажется, что не работает в коде? Или наоборот, почему код требует заполнения, когда мы этого не ожидаем?

Важно разделять два механизма:

  1. Интерактивная проверка: Свойство "Проверка заполнения" в конфигураторе влияет на работу форм. Если пользователь в интерфейсе попытается сохранить пустую запись, форма не даст этого сделать и подсветит поле красным.
  2. Ограничения СУБД: При программной записи (через Записать()) платформенные проверки интерфейса могут игнорироваться, но вступают в силу жесткие ограничения структуры базы данных (SQL). Поле периода в таблице базы данных физически не может быть NULL. Именно поэтому при попытке записать объект с пустым периодом платформа выбрасывает исключение.

Резюме

Чтобы избежать ошибки «Период не может быть пустым», при программном создании записей регистра сведений всегда следуйте алгоритму:

  1. Создайте объект (Менеджер или Набор).
  2. Явно присвойте значение свойству Период.
  3. Заполните все измерения регистра.
  4. Заполните ресурсы и реквизиты.
  5. Выполните метод Записать().

Знание таких тонкостей механизмов платформы крайне важно, если вы проходите собеседование или отбор на позицию программиста 1С, так как вопросы по работе с регистрами являются базовыми.

← На главную