Почему при записи документа табличная часть в модуле объекта оказывается пустой и как это исправить

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

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

Анализируем проблему синхронизации данных

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


// Код в модуле формы
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    Объект.ТабЧасть.Очистить();
    Для Каждого Элемент Из Список Цикл
        НоваяЗапись = Объект.ТабЧасть.Добавить();
        НоваяЗапись.Реквизит = Элемент.Значение;
    КонецЦикла;
КонецПроцедуры

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

Разберем по шагам порядок вызова событий при записи

Чтобы понять, где именно происходит сбой, проанализируем последовательность выполнения процедур:

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

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

Решение 1: Правильное использование клиентского события

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


&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    // Подготавливаем данные прямо здесь
    ЗаполнитьТабличнуюЧастьИзСписка(); 
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьТабличнуюЧастьИзСписка()
    // Работаем с реквизитом формы "Объект"
    Объект.ТабЧасть.Очистить();
    Для Каждого СтрокаСписка Из Список Цикл
        НоваяСтрока = Объект.ТабЧасть.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаСписка);
    КонецЦикла;
КонецПроцедуры

Решение 2: Использование параметра ТекущийОбъект на сервере

Если логика заполнения требует сложных серверных вычислений и вы решили использовать ПередЗаписьюНаСервере, крайне важно вносить изменения не в Объект, а в параметр ТекущийОбъект. Проанализируем правильный подход:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // ОШИБКА: Объект.ТабЧасть.Очистить(); - данные могут не синхронизироваться
    
    // ПРАВИЛЬНО: Работаем напрямую с ТекущийОбъект
    ТекущийОбъект.ТабЧасть.Очистить();
    Для Каждого Элемент Из Список Цикл
        НоваяЗапись = ТекущийОбъект.ТабЧасть.Добавить();
        НоваяЗапись.Реквизит = Элемент.Значение;
    КонецЦикла;
КонецПроцедуры

Важный нюанс: Изменения, внесенные в ТекущийОбъект, попадут в базу данных, но они не отобразятся автоматически в реквизите Объект на форме после записи, если не предпринять дополнительных действий. Однако для записи в базу это самый стабильный метод.

Почему данные могут пропадать: дополнительные факторы

Если вы уверены, что используете правильное событие, но табличная часть в модуле объекта всё равно пустая, проанализируем следующие моменты:

  1. Несоответствие типов данных. Если в СписокЗначений хранятся данные типа Строка, а реквизит табличной части имеет тип СправочникСсылка, то при передаче в модуль объекта 1С попытается привести типы. Если неявное приведение невозможно, значение станет пустым. Проверьте типизацию через ТипЗнч().
  2. Подписки на события. Посмотрите, нет ли в конфигурации подписок на событие ПередЗаписью для вашего объекта. Часто сторонние расширения или общие модули могут очищать коллекции по определенным условиям.
  3. Метод ДанныеФормыВЗначение. Если вы внутри серверного вызова вручную вызываете ДанныеФормыВЗначение(Объект, Тип("ДокументОбъект...")), вы создаете копию объекта в памяти. Любые изменения в этой копии никак не влияют на тот экземпляр объекта, который записывает сама форма.

Передача флагов управления через ПараметрыЗаписи

Иногда нужно передать из формы в модуль объекта не сами данные, а команду (например, "не пересчитывать скидки"). Для этого лучше не создавать фиктивные реквизиты, а использовать структуру ПараметрыЗаписи и свойство ДополнительныеСвойства.

Посмотрим на пример реализации:


// В модуле формы
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    ПараметрыЗаписи.Вставить("ПропускатьПроверкуЗаполнения", Истина);
КонецПроцедуры

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

Золотое правило разработки

Подведем итог: для обеспечения целостности данных всегда помните, что реквизит формы Объект — это лишь проекция данных. Если ваша задача — перелить данные из «виртуальных» элементов интерфейса в структуру документа, делайте это в клиентском ПередЗаписью. Если же вам нужно программно модифицировать объект непосредственно перед фиксацией в БД на сервере — используйте ТекущийОбъект в серверном обработчике формы. Это исключит любые неожиданности с «исчезновением» строк в табличных частях.

← На главную