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