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

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

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

Проблема: Почему очищается регистр или записывается только одна строка?

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

Важный момент: Если ваш регистр содержит тысячи записей, а вы создаете набор, добавляете в него одну строку и вызываете Записать(), в итоге в регистре останется всего одна эта строка. Все остальные данные будут удалены. Именно это и произошло у автора в первом сообщении.

Способ 1: Использование Менеджера записи (универсальный метод для точечной записи)

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

Проанализируем исправленный код, который позволяет корректно добавить или обновить запись:


Если Выборка.Ссылка = НайденнаяСсылка Тогда
    Сообщить("Запись номенклатуры: " + Выборка.Ссылка);
    
    // Создаем объект менеджера записи для конкретного регистра
    МенеджерЗаписи = РегистрыСведений.Прайс.СоздатьМенеджерЗаписи();
    
    // Заполняем измерения регистра (это ключевые поля, по которым ищется запись)
    МенеджерЗаписи.Номенклатура = Выборка.Ссылка;
    
    // Если регистр периодический, обязательно указываем период
    // МенеджерЗаписи.Период = ТекущаяДата(); 
    
    // Заполняем ресурсы (данные, которые мы храним)
    // МенеджерЗаписи.Цена = ЦенаИзExcel;
    
    // Метод Записать() проверит: если запись с такой номенклатурой есть — обновит, если нет — создаст новую
    МенеджерЗаписи.Записать();
КонецЕсли;

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

Способ 2: Использование Набора записей с установкой отбора

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


НаборПрайс = РегистрыСведений.Прайс.СоздатьНаборЗаписей();

// Устанавливаем отбор, чтобы работа велась только по конкретной номенклатуре
НаборПрайс.Отбор.Номенклатура.Установить(НайденнаяСсылка);

// Теперь можно прочитать существующую запись, если нужно
НаборПрайс.Прочитать();

Если НаборПрайс.Количество() = 0 Тогда
    // Если записи нет, создаем новую
    НоваяЗапись = НаборПрайс.Добавить();
    НоваяЗапись.Номенклатура = НайденнаяСсылка;
Иначе
    // Если запись уже есть, берем первую (единственную по этому отбору)
    НоваяЗапись = НаборПрайс[0];
КонецЕсли;

// Заполняем данные
// НоваяЗапись.Цена = НоваяЦена;

// Записываем набор. Благодаря отбору, удалятся/перезапишутся только записи по этой номенклатуре
НаборПрайс.Записать();

Почему загрузка может работать «целый час»? Оптимизация

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

1. Убираем запросы из цикла. В исходном коде автора внутри цикла Пока по строкам Excel выполняется Новый Запрос. Это критическая ошибка производительности. На каждой итерации программа обращается к базе данных, компилирует запрос и исполняет его. Как правильно: Сначала загрузите все данные из Excel в Таблицу Значений, а затем одним запросом получите все необходимые ссылки на номенклатуру или существующие цены.

2. Использование транзакций. При записи каждой строки через МенеджерЗаписи.Записать() или Набор.Записать(), 1С инициирует транзакцию в СУБД. Это требует времени на запись логов и подтверждение операции дисковой подсистемой. Рассмотрим, как ускорить процесс, обернув весь цикл загрузки в одну транзакцию:


НачатьТранзакцию();
Попытка
    // Цикл по строкам файла
    Пока СокрЛП(НоменклатураНаименование) <> "" Цикл
        // ... логика поиска и заполнения МенеджераЗаписи ...
        МенеджерЗаписи.Записать();
    КонецЦикла;
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    Сообщить("Произошла ошибка при загрузке: " + ОписаниеОшибки());
КонецПопытки;

3. Работа с COM-объектом Excel. Чтение каждой ячейки Cells(Row, Col).Value напрямую из 1С происходит медленно из-за накладных расходов на COM-взаимодействие. Совет: Гораздо быстрее прочитать весь лист Excel в массив одним махом (через UsedRange.Value) и дальше работать уже с массивом в памяти 1С.

Нюансы, которые нельзя игнорировать

  1. Периодичность регистра. Если ваш регистр Прайс является периодическим (например, цена меняется каждый день), то измерение Период является ключевым. Если вы его не укажете при записи, 1С запишет данные на дату 01.01.0001. В результате в актуальных отчетах и формах вы эти данные просто не увидите.
  2. Типы данных. Excel часто возвращает числа как тип Double. Если вы ищете номенклатуру по коду, убедитесь, что тип кода в 1С (строка или число) совпадает с тем, что пришло из Excel. Пользуйтесь функциями СокрЛП() и Число() для приведения типов.
  3. Поиск по наименованию. Это самый ненадежный способ. Лишний пробел в конце строки в Excel приведет к тому, что НайтиПоНаименованию() вернет пустую ссылку. Старайтесь использовать Артикул или Штрихкод.

Подводя итог, можно сказать: для разовых правок или небольших загрузок МенеджерЗаписи — ваш лучший друг. Для массовой обработки данных всегда используйте НаборЗаписей с четко установленными отборами и не забывайте про использование транзакций для ускорения работы системы.

← На главную