При разработке на платформе 1С:Предприятие 8.3 разработчики нередко сталкиваются с ситуацией, когда требуется дополнить существующие записи независимого регистра сведений новыми значениями. Попытка использовать метод набора записей ЗагрузитьКолонку для добавления строк часто приводит к неожиданному поведению: количество записей не увеличивается, а имеющиеся данные перезаписываются или повреждаются. Разберем по шагам, почему так происходит, и рассмотрим правильные подходы к решению этой задачи.
Проанализируем типичный ошибочный сценарий, с которым столкнулся автор вопроса:
НабЗап = РегистрыСведений.МойРегСвед.СоздатьНаборЗаписей();
НабЗап.Прочитать();
НабЗап.ЗагрузитьКолонку(НужныйМассив, "ПравильноеИмя");
НабЗап.Записать(Истина);
В этом примере после чтения в наборе находится 6 строк. Если НужныйМассив содержит элементы, разработчик ожидает увеличение общего количества записей (например, 6 + 1 = 7). Однако количество записей остается равным 6. Выясним причину такого поведения платформы.
Посмотрим на назначение и правила работы метода ЗагрузитьКолонку, зафиксированные в синтакс-помощнике платформы 1С:Предприятие:
ЗагрузитьКолонку предназначен исключительно для заполнения значений в уже существующих строках набора, а не для добавления новых строк.Таким образом, применяя данный метод к уже прочитанному набору, мы затираем данные в первых строках существующего набора, не увеличивая его размер.
Обратим внимание на вызов НабЗап.Записать(Истина) без предварительной установки отбора (Отбор). Если независимый регистр сведений перезаписывается без указания условий отбора с параметром замещения Истина, платформа очищает все остальные записи в базе данных, которые не вошли в текущий набор. Кроме того, чтение и запись всего регистра целиком приводят к блокировкам таблицы СУБД, что может парализовать работу пользователей в базе данных.
Разберем корректные способы добавления новых строк из массива в регистр сведений.
Самый надежный, простой и прозрачный способ добавить элементы массива в регистр — это последовательный перебор элементов массива с вызовом метода Добавить() у набора записей.
Если нам необходимо просто дописать новые строки в базу без предварительного считывания всей таблицы регистра, мы можем использовать пустой набор записей и метод Записать(Ложь):
НабЗап = РегистрыСведений.МойРегСвед.СоздатьНаборЗаписей();
// Обязательно устанавливаем отбор по измерению, если регистр подчинен или требуется обновить срез
// НабЗап.Отбор.Организация.Установить(ТекущаяОрганизация);
Для Каждого ЭлементМассива Из НужныйМассив Цикл
НоваяЗапись = НабЗап.Добавить();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Номенклатура = ЭлементМассива; // Пример заполнения ключевого измерения
НоваяЗапись.Количество = 1;
КонецЦикла;
// Параметр Замещать = Ложь указывает платформе не очищать существующие записи
НабЗап.Записать(Ложь);
Важное ограничение: параметр Замещать = Ложь сработает успешно только в том случае, если среди добавляемых строк нет записей с ключевыми полями (период + измерения), которые уже присутствуют в информационной базе. При совпадении ключа уникальности платформа вызовет исключение.
Если требуется добавить сразу пачку данных, платформенный метод набора Загрузить() принимает объект типа ТаблицаЗначений. Важно помнить, что метод Загрузить полностью замещает строки набора в памяти, поэтому структуру таблицы нужно сформировать заранее.
Рассмотрим, как подготовить таблицу значений для загрузки:
НабЗап = РегистрыСведений.МойРегСвед.СоздатьНаборЗаписей();
// Получаем пустую таблицу значений с точной структурой колонок регистра
ТЗ = НабЗап.ВыгрузитьКолонки();
// Добавляем в таблицу столько пустых строк, сколько элементов в массиве
Для Сч = 1 По НужныйМассив.Количество() Цикл
ТЗ.Добавить();
КонецЦикла;
// Теперь ЗагрузитьКолонку отработает корректно, так как строки в ТЗ уже созданы
ТЗ.ЗагрузитьКолонку(НужныйМассив, "Номенклатура");
// Заполняем остальные обязательные измерения для всех добавленных строк
Для Каждого СтрокаТЗ Из ТЗ Цикл
СтрокаТЗ.Период = ТекущаяДата();
СтрокаТЗ.Активность = Истина;
КонецЦикла;
// Загружаем сформированную таблицу в набор записей
НабЗап.Загрузить(ТЗ);
НабЗап.Записать(Ложь);
Когда требуется добавить всего один элемент или небольшое количество записей с проверкой существования каждой строки, часто удобнее использовать объект МенеджерЗаписи. Он работает с единичной строкой регистра и позволяет избежать блокировок целых диапазонов таблицы:
Для Каждого ЭлементМассива Из НужныйМассив Цикл
МЗ = РегистрыСведений.МойРегСвед.СоздатьМенеджерЗаписи();
МЗ.Период = ТекущаяДата();
МЗ.Номенклатура = ЭлементМассива;
// Проверяем, существует ли уже такая запись
МЗ.Прочитать();
Если Не МЗ.Выбран() Тогда
// Записи нет — заполняем ресурсы и записываем
МЗ.Активность = Истина;
МЗ.Записать();
КонецЕсли;
КонецЦикла;
ЗагрузитьКолонку оперирует только существующими индексами строк и не создает новых записей в наборе.Добавить().Замещать = Ложь и следите за установкой фильтров в свойстве Отбор, чтобы случайно не стереть данные регистра.