Как реализовать событие После записи элемента справочника в 1С:Предприятие 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

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

Метод 1. Использование асинхронных внешних событий (компонента FormEx)

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

Рассмотрим алгоритм реализации:

  1. В процедуре ПриЗаписи() модуля формы вызываем метод генерации внешнего события.
  2. Это событие попадает в очередь сообщений Windows и обрабатывается только после завершения кода 1С.
  3. В глобальном модуле прописываем реакцию на это событие.

Пример кода в модуле формы:


Процедура ПриЗаписи()
    // Основная логика записи...
    
    // Генерируем асинхронное событие через сервис FormEx
    // Передаем идентификатор, тип события и ссылку на текущий объект
    глСервис.ВнешнееСобытие("ОбменДанными", "ПослеЗаписиСправочника", ЗначениеВСтрокуВнутр(ТекущийЭлемент()));
КонецПроцедуры

В глобальном модуле в процедуре ПриОбработкеВнешнегоСобытия() мы ловим этот вызов:


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

Метод 2. Расширение формы с помощью компоненты 1С++

Выясним, как сделать решение еще более профессиональным с помощью компоненты 1С++. Она предоставляет прямой доступ к событию ПослеЗаписи через объект РасширениеФормы. Это избавляет нас от необходимости использовать внешние события и глобальный модуль.

Рассмотрим пример инициализации расширения в модуле формы:


Перем Расширение;

Процедура ПриОткрытии()
    Расширение = СоздатьОбъект("РасширениеФормы");
    Расширение.УстановитьИмяСобытия("ПослеЗаписи", "ПослеЗаписиФормы");
КонецПроцедуры

Процедура ПослеЗаписиФормы()
    // Данное событие вызывается компонентой 1С++ автоматически 
    // сразу после успешного завершения записи в БД.
    Сообщить("Элемент успешно зафиксирован в базе: " + ТекущийЭлемент());
    ВыполнитьОбмен(ТекущийЭлемент());
КонецПроцедуры

Метод 3. Принудительное перечитывание объекта (Стандартные средства)

Посмотрим на ситуацию, когда использование внешних компонент запрещено или нежелательно. Часто программисты пытаются вызвать Записать() внутри ПриЗаписи(), но сталкиваются с тем, что ТекущийЭлемент() все равно возвращает старые данные из кэша формы. Чтобы получить актуальные значения, необходимо создать отдельный объект-справочник и найти в нем текущий элемент.

Разберем этот прием:


Процедура ПриЗаписи()
    // Вызываем стандартную запись, чтобы данные ушли в буфер БД
    Записать(); 
    
    // Создаем новый контекст объекта для чтения актуальных данных
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    Если Спр.НайтиЭлемент(ТекущийЭлемент()) = 1 Тогда
        // Здесь Спр.Наименование уже будет содержать новое значение
        ВыгрузитьЗначение(Спр.Наименование);
    КонецЕсли;
КонецПроцедуры

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

Метод 4. Использование таблиц регистрации изменений (УРБД)

Проанализируем самый надежный системный способ. Если в конфигурации включена компонента "Управление распределенными информационными базами" (УРБД), система автоматически ведет учет всех измененных объектов в служебной таблице _1SUPDTS.

Преимущества этого метода:

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

Метод 5. Использование триггеров SQL (для SQL-версий)

Если ваша база работает на MS SQL Server, мы можем реализовать логику на уровне СУБД. Это "тяжелая артиллерия", которая полезна при интеграции с высоконагруженными системами.

Разберем по шагам:

  1. Создаем в SQL Server вспомогательную таблицу-очередь.
  2. Вешаем триггер AFTER UPDATE, INSERT на таблицу справочника (например, SC123).
  3. Триггер записывает ID (ROWID или ID) измененного элемента в нашу очередь.
  4. Внешний скрипт или регламентное задание 1С обрабатывает эту очередь.

Этот метод гарантирует, что вы поймаете изменение, даже если оно было сделано прямым запросом к базе данных (хотя так делать в 1С 7.7 крайне не рекомендуется).

Резюме и рекомендации

Подведем итоги нашего анализа. Выбор метода зависит от ваших технических условий:

  1. Если вам нужно быстрое решение "здесь и сейчас" без установки ВК — используйте Метод 3 (перечитывание объекта через СоздатьОбъект).
  2. Если конфигурация активно развивается и используются внешние компоненты — лучшим выбором будет Метод 1 (FormEx) или Метод 2 (1С++). Они обеспечивают наиболее чистый код.
  3. Для надежных систем обмена данными лучше всего подходит Метод 4 (использование механизмов регистрации изменений), так как он отделяет процесс записи от процесса обмена, повышая отказоустойчивость системы.

Помните, что архитектура 1С 7.7 требует особого внимания к транзакциям. Любые длительные операции (например, отправка данных по HTTP или запись в тяжелый файл) лучше выносить за пределы процедуры ПриЗаписи(), чтобы не блокировать работу других пользователей в базе данных.

← На главную