Почему в регистре сведений 1С сохраняется только одна запись вместо нескольких и как это исправить?

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

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

Анализ проблемы: уникальность ключа записи

Рассмотрим ситуацию, с которой столкнулся автор темы. Имеется регистр сведений со следующей структурой:

  1. Измерение: ДокументРеестрЛимитов (тип: Ссылка на документ).
  2. Ресурс: ТипУведомления (тип: Перечисление).

Автор пытается записать несколько уведомлений по одному и тому же документу подряд, используя МенеджерЗаписи:


МенеджерЗаписи = РегистрыСведений.ХХХ_УведомленияРеестраЛимитов.СоздатьМенеджерЗаписи(); 
МенеджерЗаписи.ХХХ_ДокументРеестрЛимитов = Ссылка; 
МенеджерЗаписи.ХХХ_ТипУведомления = Перечисления.ХХХ_ТипУведомленияРеестраЛимитов.ХХХ_УведомлениеАктуализировано; 
МенеджерЗаписи.Записать();

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

Решение №1: Добавление дополнительного измерения

Если ваша задача — хранить информацию о том, что по документу были отправлены уведомления разных типов, самым правильным решением будет вынос типа уведомления из ресурсов в измерения. Проанализируем, как изменится ключ записи. Теперь ключом будет связка: {Документ + ТипУведомления}.

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


// Запись первого типа уведомления
МенеджерЗаписи = РегистрыСведений.ХХХ_УведомленияРеестраЛимитов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ХХХ_ДокументРеестрЛимитов = Ссылка;
МенеджерЗаписи.ХХХ_ТипУведомления = Перечисления.ХХХ_ТипУведомленияРеестраЛимитов.Тип1;
МенеджерЗаписи.Записать();

// Запись второго типа уведомления для того же документа
МенеджерЗаписи = РегистрыСведений.ХХХ_УведомленияРеестраЛимитов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ХХХ_ДокументРеестрЛимитов = Ссылка;
МенеджерЗаписи.ХХХ_ТипУведомления = Перечисления.ХХХ_ТипУведомленияРеестраЛимитов.Тип2;
МенеджерЗаписи.Записать();

В этом случае в регистре появятся две независимые строки, так как их ключи уникальны.

Решение №2: Использование периодичности

Если необходимо фиксировать несколько однотипных событий во времени (например, несколько уведомлений одного и того же типа, отправленных в разное время), регистр следует сделать периодическим. В периодическом регистре к ключу уникальности добавляется поле Период.

Рассмотрим важный нюанс, упомянутый в обсуждении. Если вы установите периодичность "В пределах секунды" и попытаетесь сделать две записи в одном цикле кода, велика вероятность, что они все равно перезапишут друг друга. Это происходит потому, что код выполняется быстрее чем за одну секунду, и функция ТекущаяДата() вернет одинаковое значение для обеих записей.

Посмотрим на пример, который может привести к ошибке:


МенеджерЗаписи = РегистрыСведений.ХХХ_УведомленияРеестраЛимитов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДата(); // Допустим, сейчас 12:00:01
МенеджерЗаписи.ХХХ_ДокументРеестрЛимитов = Ссылка;
МенеджерЗаписи.Записать();

// Прошло 0.001 сек, ТекущаяДата() все еще 12:00:01
МенеджерЗаписи = РегистрыСведений.ХХХ_УведомленияРеестраЛимитов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДата(); 
МенеджерЗаписи.ХХХ_ДокументРеестрЛимитов = Ссылка;
МенеджерЗаписи.Записать(); // Перезапишет предыдущую!

Чтобы избежать этого при использовании периодичности, часто добавляют дополнительное измерение (например, НомерСтроки или УникальныйИдентификатор) или используют периодичность "Позиция регистратора", если записи подчинены документу.

Решение №3: Работа с Набором Записей

Использование объекта РегистрСведенийМенеджерЗаписи удобно для точечной работы с одной строкой, но не всегда эффективно для массовой записи. Разберем, как сделать то же самое через НаборЗаписей. Это более профессиональный подход, особенно если запись происходит внутри транзакции или при проведении документа.


НаборЗаписей = РегистрыСведений.ХХХ_УведомленияРеестраЛимитов.СоздатьНаборЗаписей();
// Устанавливаем фильтр по измерениям, чтобы не затереть лишнее
НаборЗаписей.Отбор.ХХХ_ДокументРеестрЛимитов.Установить(Ссылка);

// Формируем первую строку
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ХХХ_ДокументРеестрЛимитов = Ссылка;
НоваяЗапись.ХХХ_ТипУведомления = Перечисления.ХХХ_ТипУведомленияРеестраЛимитов.Тип1;

// Формируем вторую строку
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ХХХ_ДокументРеестрЛимитов = Ссылка;
НоваяЗапись.ХХХ_ТипУведомления = Перечисления.ХХХ_ТипУведомленияРеестраЛимитов.Тип2;

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

Важно: При использовании метода Записать() у набора записей с установленным отбором, старые записи в базе, попадающие под этот отбор, будут удалены и заменены новыми из набора. Это отличный способ контролировать актуальность данных.

Выбор между Ресурсом, Измерением и Реквизитом

Чтобы в будущем не возникало подобных проблем, проанализируем, как правильно выбирать тип поля в регистре:

В случае автора темы, ТипУведомления должен быть именно измерением, так как бизнес-логика предполагает наличие нескольких типов уведомлений по одному документу одновременно. Если же нужно знать только последнее отправленное уведомление, тогда это поле остается ресурсом в непериодическом регистре.

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

← На главную