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