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