Почему после программного создания связи документов вкладка «Связи» остается пустой?

Программист 1С v8.3 (Управляемые формы) 1С:Документооборот IT и автоматизация бизнеса
← На главную

Рассмотрим распространенную ситуацию при разработке в 1С:Документооборот (или конфигурации ДГУ), с которой часто сталкиваются программисты. Мы программно создаем исходящий или внутренний документ, а затем, также программно, устанавливаем для него связь с уже существующим входящим документом. В базе данных записи появляются, регистр сведений заполнен корректно, однако если мы посмотрим на открытую форму входящего документа — вкладка «Связи» остается пустой. Связи появляются только после полного закрытия и повторного открытия формы, а иногда и вовсе после перезапуска сеанса.

Разберем по шагам, почему возникает эта проблема, проанализируем типичный код создания связей и выясним, как правильно оповещать систему об изменениях, чтобы интерфейс пользователя обновлялся мгновенно.

Анализ программного создания связи

Посмотрим на пример кода, который часто пишут разработчики для установки связей между документами. В данном случае программист делает прямую запись в регистр сведений СвязиДокументов:


ТипыСвязи = ПолучитьТипыСвязи(ВнутреннийДокумент.ВидДокумента, ВнутреннийДокумент_Связь.ВидДокумента);
Если ТипЗнч(ТипыСвязи) = Тип("Структура") Тогда
    
    // Создаем прямую связь
    Запись = РегистрыСведений.СвязиДокументов.СоздатьМенеджерЗаписи();
    Запись.ДатаУстановки = ТекущаяДата();
    Запись.Документ = ВнутреннийДокумент;
    Запись.СвязанныйДокумент = ВнутреннийДокумент_Связь;
    Запись.ТипСвязи = ТипыСвязи.ТипСвязи;
    Запись.Установил = ТекущийПользователь;
    Запись.Записать();
    
    // Создаем обратную связь
    Запись = РегистрыСведений.СвязиДокументов.СоздатьМенеджерЗаписи();
    Запись.ДатаУстановки = ТекущаяДата();
    Запись.Документ = ВнутреннийДокумент_Связь;
    Запись.СвязанныйДокумент = ВнутреннийДокумент;
    Запись.ТипСвязи = ТипыСвязи.ТипОбратнойСвязи;
    Запись.Установил = ТекущийПользователь;
    Запись.Записать();

КонецЕсли;

На первый взгляд, все сделано логично: мы создаем две записи (прямую и обратную) через менеджер записи. Но после выполнения этого кода у пользователя, у которого в данный момент открыта карточка ВнутреннийДокумент_Связь, ничего визуально не меняется.

Выясняем причину пустого списка связей

Проанализируем ситуацию с точки зрения архитектуры платформы 1С:Предприятие. Когда пользователь открывает форму входящего или внутреннего документа, платформа считывает данные из базы данных и помещает их в кэш формы. Вкладка связей, которая обычно реализована через динамический список или дерево значений, формируется на момент открытия.

Когда наш фоновый или программный алгоритм делает запись напрямую в регистр сведений, платформа не знает, что эта запись как-то влияет на уже открытые формы. Метод Записать() отрабатывает «за кулисами». Форма документа уже прочитала свои данные и закэшировала их. Визуально связи не будут отображаться до тех пор, пока пользователь вручную не переоткроет форму, инициировав новый запрос к базе данных.

Решение 1: Программное обновление кэша и интерфейса

Чтобы открытые формы моментально узнали об изменениях в базе данных, нам необходимо принудительно сбросить кэш и подать платформе сигнал на перерисовку интерфейса. Воспользуемся глобальным методом платформы ОповеститьОбИзменении.

После того как вы выполнили метод Записать() для регистра сведений, добавьте следующий код:


ОповеститьОбИзменении(ВнутреннийДокумент.Ссылка);
ОповеститьОбИзменении(ВнутреннийДокумент_Связь.Ссылка);

Этот метод очищает локальный кэш данных указанных ссылочных объектов. Если у пользователя открыты формы этих документов, система автоматически постарается актуализировать отображаемые данные.

Решение 2: Событийная модель (Оповещение форм)

В некоторых сложных конфигурациях (какой является 1С:Документооборот) простого сброса кэша бывает недостаточно, особенно если связи выводятся в программно заполняемое дерево значений. В таком случае мы применим событийную модель.

В месте создания связи мы генерируем глобальное событие:

Оповестить("ОбновленыСвязи", , ВнутреннийДокумент_Связь.Ссылка);

А в модуле формы документа (например, в расширении или измененной типовой форме), в стандартном обработчике ОбработкаОповещения, мы перехватываем этот сигнал:


&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Если ИмяСобытия = "ОбновленыСвязи" И Источник = Объект.Ссылка Тогда
        // Принудительно обновляем элемент формы (динамический список или дерево)
        Элементы.ДеревоСвязей.Обновить();
        // Или перечитываем форму целиком
        ЭтаФорма.Прочитать();
    КонецЕсли;
КонецПроцедуры

Решение 3: Использование типового API 1С:Документооборота (Лучшая практика)

Рассмотрим более правильный подход. В сложных конфигурациях делать прямую запись в РегистрыСведений.СвязиДокументов считается антипаттерном. Разработчики конфигурации уже предусмотрели специальный программный интерфейс (API), который сам заботится о проверках, кэше и оповещениях.

В 1С:Документооборот для работы со связями существуют экспортные методы в общих модулях, таких как СвязиДокументовСервер или РаботаСоСвязямиДокументов.

Вместо ручного создания менеджера записи используйте вызов типовой функции. Это может выглядеть так (название модуля зависит от версии конфигурации):


// Пример использования типового API
ПараметрыСвязи = Новый Структура;
ПараметрыСвязи.Вставить("Документ", ВнутреннийДокумент);
ПараметрыСвязи.Вставить("СвязанныйДокумент", ВнутреннийДокумент_Связь);
ПараметрыСвязи.Вставить("ТипСвязи", ТипыСвязи.ТипСвязи);

СвязиДокументовСервер.ДобавитьСвязь(ПараметрыСвязи);

Преимущества данного подхода:

  1. Типовые методы самостоятельно вызывают ОповеститьОбИзменении.
  2. Система проверяет настройки: единичная это связь или множественная.
  3. Исключается нарушение целостности данных (например, защита от дублей).

Решение 4: Настройки автоматической обратной связи

Обратим внимание еще на один нюанс в исходном коде: разработчик вручную пишет две записи — для прямой и обратной связи. В 1С:Документооборот в справочнике «Типы связей» уже заложена настройка двусторонней связи.

Если в настройках конкретного типа связи указано, что она является взаимной (например, «Отправлен в ответ на» генерирует обратную связь «Отправлен ответ»), то при записи одной связи система автоматически создаст вторую. Попытка вручную добавить вторую связь программно может привести к коллизиям в базе данных, дублям или блокировкам транзакций. Именно из-за таких неявных ошибок система может вести себя нестабильно, а данные «появляться» только после перезапуска клиента.

Резюмируем наши действия: При программном создании связей старайтесь использовать типовые экспортные процедуры конфигурации. Если же вам необходимо писать напрямую в регистр — не забывайте инвалидировать кэш платформы с помощью ОповеститьОбИзменении и, при необходимости, принудительно обновлять элементы открытых форм через механизм оповещений.

← На главную