Почему в 1С 7.7 при записи документа контекст возвращает старые значения реквизитов и как это исправить

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

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

Проанализируем причины такого поведения и разберем по шагам рабочие методы решения этой задачи.

Суть проблемы: разрыв между данными и их представлением

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

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


Функция глЕстьСерииСМДЛП(Конт) Экспорт
    Конт.ВыбратьСтроки();
    Пока Конт.ПолучитьСтроку() = 1 Цикл
        // Обращение к реквизиту реквизита ТЧ
        Если Конт.Серия.МДЛП = 1 Тогда
            Возврат 1;
        КонецЕсли;
    КонецЦикла;
    Возврат 0;
КонецФункции

Проблема заключается в том, что если значение в поле Серия было только что изменено программно, обращение Конт.Серия.МДЛП может вернуть состояние, актуальное для предыдущего значения серии. Это происходит из-за особенностей внутреннего кэширования объектов в 1С 7.7.

Выясним причину: эффект отладчика и внутренний кэш

Многих разработчиков сбивает с толку то, что при остановке в отладчике код начинает работать правильно. Это происходит из-за так называемого «побочного эффекта» инспекции переменных. Когда вы открываете табло или нажимаете Shift+F9 на переменной Конт.Серия, отладчик принудительно обращается к базе данных, чтобы получить актуальное представление объекта. Это действие заставляет платформу обновить внутренний указатель на объект, и последующее выполнение кода проходит корректно.

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

Решение №1: Принудительное обновление формы

Самый простой, хотя и не всегда очевидный способ синхронизировать данные визуального контекста с внутренней структурой объекта — это использование метода Форма.Обновить(). Вызов этого метода перед выполнением проверок в процедуре ПриЗаписи() заставляет платформу перечитать значения из элементов управления и сбросить кэшированные связи реквизитов.

Пример использования в модуле формы документа:


Процедура ПриЗаписи()
    // Принудительно синхронизируем контекст
    Форма.Обновить();
    
    // Теперь вызываем проверку
    Если глЕстьСерииСМДЛП(Контекст) = 1 Тогда
        // Логика обработки
    КонецЕсли;
КонецПроцедуры

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

Решение №2: Использование выгрузки в таблицу значений

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

Рассмотрим, как изменить подход к проверке:


// В модуле документа
ТЗ_Данных = СоздатьОбъект("ТаблицаЗначений");
ВыгрузитьТабличнуюЧасть(ТЗ_Данных);

// Передаем таблицу в функцию вместо контекста
Если глПроверитьДанныеТЗ(ТЗ_Данных) = 1 Тогда
    // Действия
КонецЕсли;

Такой подход гарантирует, что вы работаете с текущими значениями ссылок, которые находятся в объекте «Документ» в данный конкретный момент, минуя особенности визуального обновления полей формы.

Решение №3: Явное создание объекта справочника

Если вам нужно получить реквизит связанного объекта (реквизит реквизита), и вы не хотите полагаться на «точечную» нотацию Конт.Реквизит.Свойство, можно прибегнуть к явному созданию объекта справочника. Это наиболее «чистый» с точки зрения архитектуры 7.7 способ, так как он гарантирует получение данных непосредственно из базы или транзакционного кэша.

Проанализируем модифицированный код функции:


Функция глЕстьСерииСМДЛП_Надежная(Конт) Экспорт
    Перем СпрСерии;
    СпрСерии = СоздатьОбъект("Справочник.Серии");
    
    Конт.ВыбратьСтроки();
    Пока Конт.ПолучитьСтроку() = 1 Цикл
        // Вместо прямого обращения через точку
        // Находим элемент в отдельном объекте
        Если СпрСерии.НайтиЭлемент(Конт.Серия) = 1 Тогда
            Если СпрСерии.МДЛП = 1 Тогда
                Возврат 1;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Возврат 0;
КонецФункции

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

  1. Надежность: Вы не зависите от состояния контекста формы.
  2. Предсказуемость: Объект СпрСерии всегда содержит актуальные данные для переданной ссылки.
  3. Отладка: Поведение кода в режиме предприятия будет полностью соответствовать поведению в отладчике.

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

Подводя итог, можно сказать, что «непонятное» поведение платформы 1С 7.7 при обращении к реквизитам через контекст — это следствие оптимизации работы с памятью и экранными формами. Для решения подобных проблем мы рекомендуем:

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

← На главную