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

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

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

Анализ проблемы: почему записи «схлопываются»

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

Проанализируем ситуацию: если у вашего регистра есть измерения ОбъектОИС и Код, и вы пытаетесь записать десять строк, где эти два поля идентичны, система 1С будет воспринимать каждую последующую запись не как новую строку, а как обновление уже существующей. Платформа просто «перезаписывает» данные в ресурсах и реквизитах для данного ключа. В итоге, сколько бы итераций цикла вы ни сделали, в базе данных физически будет существовать только одна запись с данным набором измерений.

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

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

  1. Измерение «НомерКопии» (тип Число): При записи в цикле мы передаем индекс итерации в это измерение.
  2. Измерение «ИдентификаторЗаписи» (тип УникальныйИдентификатор): Это гарантирует 100% уникальность, даже если другие данные полностью совпадают.

Посмотрим на пример правильной реализации с использованием дополнительного измерения НомерКопии:


Для н = 1 По КоличествоКопий Цикл
    // Создаем набор с отбором по основным измерениям
    Набор = РегистрыСведений.КомпьютерыИОргтехника.СоздатьНаборЗаписей();
    Набор.Отбор.ОбъектОИС.Установить(ЭтотОбъект.Ссылка);
    Набор.Отбор.Код.Установить(ЭтотОбъект.Код);
    Набор.Отбор.НомерКопии.Установить(н); // Каждая итерация — уникальный ключ
    
    НоваяЗапись = Набор.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяЗапись, ВыборкаПК);
    НоваяЗапись.ОбъектОИС = ЭтотОбъект.Ссылка;
    НоваяЗапись.Код = ЭтотОбъект.Код;
    НоваяЗапись.НомерКопии = н;
    
    Набор.Записать();
КонецЦикла;

Решение №2: Оптимизация работы с Набором записей

Рассмотрим критическую ошибку производительности, которая часто встречается в коде. В примере выше Набор.Записать() вызывается внутри цикла. Это крайне неэффективно, так как при каждой итерации программа обращается к СУБД, открывает транзакцию и блокирует таблицу. Если копий будет много (например, 100 или 1000), система начнет заметно «тормозить».

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

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

Рассмотрим правильный алгоритм массовой записи:


// 1. Создаем набор записей
Набор = РегистрыСведений.КомпьютерыИОргтехника.СоздатьНаборЗаписей();

// 2. Устанавливаем отбор по владельцу (ОбъектОИС), чтобы не затереть лишнее
Набор.Отбор.ОбъектОИС.Установить(ЭтотОбъект.Ссылка);

// 3. Заполняем коллекцию записей в цикле
Для н = 1 По КоличествоКопий Цикл
    НовЗапись = Набор.Добавить();
    НовЗапись.ОбъектОИС = ЭтотОбъект.Ссылка;
    НовЗапись.Код = ЭтотОбъект.Код;
    НовЗапись.НомерКопии = н; // Позволяет добавить несколько строк в один набор
    
    // Заполнение остальных полей
    НовЗапись.Изготовитель = ВыборкаПК.Изготовитель;
    НовЗапись.МодельУстройства = ВыборкаПК.МодельУстройства;
    // ... заполнение остальных ресурсов ...
КонецЦикла;

// 4. Записываем весь массив данных за одно обращение к БД
Набор.Записать();

Опасность использования Прочитать() без отборов

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

Золотое правило: Всегда устанавливайте фильтры в объекте НаборЗаписей.Отбор перед чтением или записью. Если ваша задача — добавить новые записи к существующим, вам нужно:

  1. Установить отбор по измерениям.
  2. Вызвать Набор.Прочитать() (это загрузит существующие в базе строки в коллекцию набора).
  3. Использовать Набор.Добавить() для добавления новых строк.
  4. Вызвать Набор.Записать().

Альтернативный подход: Архитектурное решение

Проанализируем ситуацию с точки зрения проектирования базы данных. Если вам нужно хранить информацию о том, что у одного объекта есть «10 копий», создание десяти физических строк в регистре сведений — не всегда лучшее решение. Это увеличивает объем базы и усложняет запросы.

Рассмотрим альтернативы:

Итоги и рекомендации

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

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

Соблюдение этих принципов обеспечит стабильную работу системы и высокую скорость записи данных в регистры 1С.

← На главную