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

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

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

Анализируем проблему: почему НаборЗаписей или МенеджерЗаписи ведут себя странно

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

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

Посмотрим на пример кода с ошибкой:


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

Решение №1: Правильное использование МенеджераЗаписи

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

Разберем по шагам правильный цикл:

  1. Внутри цикла создаем новый объект СоздатьМенеджерЗаписи().
  2. Устанавливаем ключевые поля: Период и все измерения (в нашем случае Физлицо).
  3. Заполняем ресурсы.
  4. Вызываем метод Записать(). Если запись с таким ключом уже есть, она будет обновлена. Если нет — создана новая.

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

Решение №2: Массовое удаление через НаборЗаписей (Оптимальный способ)

Удаление записей по одной через МенеджерЗаписи в цикле — это медленно и создает лишнюю нагрузку на базу данных. Проанализируем более эффективный подход с использованием РегистрСведенийНаборЗаписей. Чтобы удалить все записи по конкретному физическому лицу, достаточно записать пустой набор с установленным фильтром.

Рассмотрим, как это сделать правильно:


Набор = РегистрыСведений.СведенияОСтажеРаботыНаСевере.СоздатьНаборЗаписей();
Набор.Отбор.Физлицо.Установить(ФизлицоСсылка);

// Вызов Записать() с пустым набором удаляет все записи из базы, 
// которые соответствуют установленному отбору.
Набор.Записать(Истина); 

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

Решение №3: Комплексная перезагрузка данных (Удаление + Запись)

Выясним причину, по которой у автора не получалось обновить данные. Ему нужно было удалить старые сведения по сотруднику и загрузить новые из файла. Самый надежный способ сделать это — использовать НаборЗаписей для каждого сотрудника.

Рассмотрим пошаговый алгоритм совместной работы с файлом и регистром:

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

Пример кода для комплексного обновления:


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

// Очищать существующие записи в базе явно не нужно, 
// так как Записать(Истина) сделает это автоматически в пределах отбора.

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

Попытка
    Набор.Записать(Истина);
Исключение
    Сообщить("Ошибка при записи данных по сотруднику: " + ОписаниеОшибки());
КонецПопытки;

Важные замечания по периодичности

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

Помните:

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

← На главную