При выполнении масштабного обновления конфигурации «Зарплата и управление персоналом», особенно при переходе с редакции 2.5 на 3.1, системные администраторы и программисты часто сталкиваются с критической остановкой процесса. Ошибка в строке 99 модуля ОбновлениеИнформационнойБазы с текстом «Ошибка при вызове метода контекста (Записать)» обычно свидетельствует о том, что программа пытается программно изменить или пересчитать данные, но наталкивается на нарушение уникальности записей в базе данных.
Рассмотрим детально, почему это происходит и какими способами можно восстановить работоспособность информационной базы.
Проанализируем техническую сторону вопроса. В процессе обновления конфигурация выполняет обработчики обновления, которые реструктуризируют данные. В редакции 3.1 структура регистра сведений КадроваяИсторияСотрудников претерпела значительные изменения по сравнению с ранними версиями и переходными релизами (такими как 3.0). Изменился состав ключевых полей (измерений), по которым платформа определяет уникальность каждой записи.
Если в вашей базе после перехода с 2.5 остались записи, которые в старой структуре считались уникальными, а в новой — становятся идентичными, система выдает ошибку при попытке записи набора. Основными факторами конфликта являются:
СправочникСсылка.Сотрудники ссылаются на одну и ту же комбинацию кадровых данных.Если записей немного, мы можем устранить проблему вручную. Для этого проанализируем состояние регистра КадроваяИсторияСотрудников. Перейдем в функции технического специалиста и откроем данный регистр. Поищем сотрудников, по которым визуально наблюдается «задвоение» строк на одну и ту же дату или по одному и тому же регистратору.
Зачастую в пользовательском интерфейсе (в самом документе) мы видим одну строку, но в базе данных их две. Это происходит из-за того, что документ при проведении не смог корректно очистить старые движения. В этом случае следует:
Рассмотрим более эффективный метод для случаев, когда дублей много. Суть метода заключается в полной очистке регистра КадроваяИсторияСотрудников перед запуском обновления. Это позволит процедурам обновления создать новые, корректные записи «с чистого листа» на основании документов.
Важно: Перед выполнением этих действий обязательно создайте резервную копию базы данных!
Алгоритм действий:
Для программной очистки регистра можно использовать следующий фрагмент кода:
НаборЗаписей = РегистрыСведений.КадроваяИсторияСотрудников.СоздатьНаборЗаписей();
НаборЗаписей.Записать(); // Пустой набор запишет пустоту во всю таблицу
Этот метод хорош тем, что он устраняет саму почву для конфликта уникальности, позволяя платформе сформировать новые измерения согласно актуальной логике релиза 3.1.8 и выше.
Чтобы не гадать, по каким именно сотрудникам возникла проблема, проанализируем ситуацию с помощью консоли запросов. Нам необходимо сгруппировать данные по всем измерениям регистра и найти те комбинации, где количество записей больше одной.
Пример структуры запроса для выявления проблемных мест:
ВЫБРАТЬ
КадроваяИстория.Сотрудник,
КадроваяИстория.Период,
КадроваяИстория.Организация,
КОЛИЧЕСТВО(*) КАК КоличествоДублей
ИЗ
РегистрСведений.КадроваяИсторияСотрудников КАК КадроваяИстория
СГРУППИРОВАТЬ ПО
КадроваяИстория.Сотрудник,
КадроваяИстория.Период,
КадроваяИстория.Организация
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
Разберем результат выполнения запроса: если список не пуст, значит, именно эти сотрудники блокируют обновление. Проанализируем каждую запись и выясним, какой из документов (регистраторов) создал лишнюю строку.
Если мы решили исправлять данные программно, важно помнить о механизмах платформы, которые могут блокировать запись «неправильных» с точки зрения конфигурации данных. Для обхода проверок при записи набора записей в коде следует использовать свойство ОбменДанными.Загрузка.
Рассмотрим пример кода, который перезаписывает движения документа, игнорируя встроенные проверки:
Набор = РегистрыСведений.КадроваяИсторияСотрудников.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СсылкаНаДокумент);
Набор.Прочитать();
// Здесь можно выполнить логику по удалению конкретной записи из набора
// ...
Набор.ОбменДанными.Загрузка = Истина;
Набор.Записать();
Использование флага Загрузка = Истина позволяет «протолкнуть» запись в базу данных даже в тех случаях, когда типовые модули 1С:ЗУП пытаются этому воспрепятствовать из-за внутренних алгоритмов контроля.
Иногда причина ошибки кроется не в логических дублях, а в физическом повреждении таблиц или индексов базы данных. Проанализируем состояние базы через Конфигуратор. Выполним процедуру «Тестирование и исправление» со следующими настройками:
В поле «При наличии ссылок на несуществующие объекты» выберем «Очищать объекты». Это поможет избавиться от «битых» записей в регистре, которые ссылаются на удаленные документы, что часто случается при прерванных переходах с версии 2.5.
Выясним еще один важный нюанс: релиз 3.1.8 был «переломным» для архитектуры ЗУП. Если вы обновляетесь с очень старого релиза (например, 3.1.5), попробуйте выполнить обновление поэтапно. Не прыгайте сразу на самый свежий релиз. Сначала обновитесь до ближайшего стабильного LTSC-релиза, выполните все процедуры обновления в пользовательском режиме, убедитесь, что регистр КадроваяИсторияСотрудников заполнен корректно, и только потом двигайтесь дальше.
Подводя итог, можно сказать, что ошибка «Записать» в модуле обновления почти всегда излечима путем очистки или нормализации регистра кадровой истории. Главное — четко определить виновника дублирования через запрос и не бояться использовать программные средства для очистки регистров перед повторным запуском обновления.