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

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

При переходе с обычных форм на управляемые разработчики часто сталкиваются с ситуацией, когда табличная часть, заполненная на форме, оказывается пустой при попытке обработать её через процедуры модуля объекта. Попытки решить проблему прямой записью объекта из контекста формы через РеквизитФормыВЗначение нередко приводят к другой критической ошибке: «Операция не может быть выполнена из-за несоответствия версии или отсутствия записи базы данных (возможно, запись была изменена или удалена)!».

Разберем подробно причины такого поведения платформы 1С:Предприятие 8.3 и рассмотрим правильные архитектурные способы обработки данных табличных частей.

Выясним причину: разница между данными формы и объектом базы

Проанализируем, почему табличная часть кажется пустой и откуда берется ошибка версии:

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

Вариант 1. Обработка данных непосредственно в контексте формы

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


&НаСервере 
Процедура ЗаполнитьТаблицуПолуфабрикаты(Идентификатор, Цех, пПродукция)
    Отбор = Новый Структура;    
    СтрокаПолуфабриката = Дерево.НайтиПоИдентификатору(Идентификатор);
        
    Отбор.Вставить("Номенклатура", СтрокаПолуфабриката.СтрокаНаименование);
    Отбор.Вставить("ЦехПроизводства", Цех);
    
    нСтроки = Объект.Полуфабрикаты.НайтиСтроки(Отбор);
    Если нСтроки.Количество() <> 0 Тогда
        нСтрока = нСтроки[0];
        нСтрока.Количество = нСтрока.Количество + СтрокаПолуфабриката.Количество;
    Иначе
        НоваяСтрокаПолуфабриката = Объект.Полуфабрикаты.Добавить();
        НоваяСтрокаПолуфабриката.Продукция        = пПродукция;
        НоваяСтрокаПолуфабриката.Номенклатура     = СтрокаПолуфабриката.СтрокаНаименование;
        НоваяСтрокаПолуфабриката.ЦехПроизводства  = Цех;
        НоваяСтрокаПолуфабриката.Количество       = СтрокаПолуфабриката.Количество;
    КонецЕсли;
КонецПроцедуры

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

Вариант 2. Вынос логики в модуль менеджера или общий модуль

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

Разберем по шагам, как преобразовать коллекцию формы в универсальную таблицу значений, передать её на обработку и вернуть результат на форму:


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

В модуле менеджера процедура принимает готовую таблицу значений:


// В модуле менеджера документа
Процедура ВыполнитьРасчет(ТаблицаПолуфабрикатов) Экспорт
    Для Каждого Стр Из ТаблицаПолуфабрикатов Цикл
        // Выполнение алгоритма обработки строк
    КонецЦикла;
КонецПроцедуры

Вариант 3. Корректная работа с прикладным объектом из формы

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

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


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

Важное правило: если в пользовательском сценарии действительно необходимо сохранить документ из формы, не используйте метод ДокументОбъект.Записать(). Используйте платформенный метод самой формы ЭтотОбъект.Записать() (или команду ЗаписатьВФорме()). Это обеспечит штатное прохождение всех событий формы, корректную фиксацию транзакции и автоматическое обновление версии данных без ошибок блокировки.

← На главную