В процессе разработки на платформе 1С программисты часто сталкиваются с задачей синхронизации состояний различных объектов. Типичный пример: при проведении экзаменационной ведомости необходимо обновить статус заявления в анкете абитуриента. На первый взгляд кажется логичным просто найти нужный документ, изменить в нем реквизит и сохранить. Однако такой подход таит в себе множество подводных камней, от критических ошибок блокировок до нарушения целостности данных.
В этой статье мы разберем, почему прямое изменение одного документа из модуля другого считается «антипаттерном», и рассмотрим наиболее эффективные и профессиональные способы решения этой задачи, принятые в стандартах разработки 1С.
Рассмотрим ситуацию, когда мы используем метод ПолучитьОбъект() и Записать() для изменения анкеты прямо в коде проведения ведомости. Почему это плохо? Проанализируем основные причины:
ОбработкаУдаленияПроведения, чтобы попытаться вернуть «как было».Самый правильный архитектурный подход — это вынос изменяемых состояний в Периодический регистр сведений. Давайте разберем этот механизм по шагам.
Вместо того чтобы хранить статус «Подано/Отозвано» в табличной части документа АнкетаАбитуриента, мы создадим регистр СтатусыЗаявлений. Это позволит нам не менять документы «прошлого», а просто фиксировать новое событие в истории.
Шаг 1. Настройка регистра:
Создадим регистр сведений со следующими параметрами:
Абитуриент (СправочникСсылка), КонкурснаяГруппа (СправочникСсылка).Статус (ПеречислениеСсылка.СтатусыЗаявлений).Шаг 2. Запись данных из документов:
Теперь документ Анкета при проведении будет делать запись в этот регистр со статусом Подано. А документ ЭкзаменационнаяВедомость при проведении создаст новую запись с тем же набором измерений, но со статусом НеПрошел (или Отозвано).
Проанализируем пример кода в процедуре ОбработкаПроведения для документа ЭкзаменационнаяВедомость:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Удаляем старые записи по этому регистратору, чтобы избежать дублирования
Движения.СтатусыЗаявлений.Записывать = Истина;
Движения.СтатусыЗаявлений.Очистить();
Для Каждого СтрокаВедомости Из ТабличнаяЧастьЭкзамены Цикл
Если СтрокаВедомости.Результат = Перечисления.РезультатыЭкзамена.НеСдал Тогда
НоваяЗапись = Движения.СтатусыЗаявлений.Добавить();
НоваяЗапись.Период = Дата;
НоваяЗапись.Абитуриент = СтрокаВедомости.Абитуриент;
НоваяЗапись.КонкурснаяГруппа = СтрокаВедомости.КонкурснаяГруппа;
НоваяЗапись.Статус = Перечисления.СтатусыЗаявлений.Отозвано;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
При такой схеме, если ведомость будет отменена, запись в регистре исчезнет автоматически, и система снова будет «видеть» предыдущий актуальный статус, записанный анкетой.
Теперь, когда данные хранятся в регистре, нам не нужно искать их в анкете. Для формирования документа РейтингАбитуриентов или любого отчета мы будем использовать виртуальную таблицу СрезПоследних. Рассмотрим, как составить запрос, который выберет только тех, кто успешно сдал экзамены.
Разберем пример запроса:
ВЫБРАТЬ
СтатусыСрезПоследних.Абитуриент КАК Абитуриент,
СтатусыСрезПоследних.Статус КАК ТекущийСтатус
ИЗ
РегистрСведений.СтатусыЗаявлений.СрезПоследних(&ДатаРейтинга, ) КАК СтатусыСрезПоследних
ГДЕ
СтатусыСрезПоследних.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаявлений.Отозвано)
Этот подход гарантирует, что вы всегда работаете с самой свежей информацией, не перегружая базу данных лишними операциями записи документов.
Если ваша конфигурация предполагает, что логика изменения статусов должна быть отделена от кода самих документов (например, вы работаете в расширении или не хотите менять типовой код), используйте Подписки на события.
Создадим объект ПодпискаНаСобытие:
ДокументОбъект.ЭкзаменационнаяВедомость.ОбработкаПроведения.В обработчике мы реализуем ту же логику записи в регистр. Это делает систему более гибкой: если завтра появится новый документ «Апелляция», который тоже должен влиять на статус, мы просто добавим его в источники этой же подписки.
Часто возникает вопрос: «Но как пользователь увидит статус в самой анкете, если мы его там не сохраняем?». Решение очень простое — динамическое отображение.
Выясним, как это сделать программно:
В форме документа АнкетаАбитуриента в обработчике ПриЧтенииНаСервере или ПриСозданииНаСервере можно выполнить быстрый запрос к регистру сведений и вывести результат в декорацию (надпись) или в реквизит формы, не связанный с данными объекта. Таким образом, пользователь всегда видит актуальное состояние, а база данных остается стройной и производительной.
Резюмируем:
1. Никогда не меняйте один документ из другого напрямую через ПолучитьОбъект(), если этого можно избежать.
2. Всегда используйте регистры сведений для хранения состояний и статусов, которые меняются во времени.
3. Используйте виртуальные таблицы СрезПоследних для получения актуальной информации.
4. Помните о транзакциях: данные в регистрах, подчиненных регистратору, живут и умирают вместе с проведением документа, что обеспечивает идеальную целостность системы.