Почему возникает ошибка «Метод недоступен на клиенте» при вызове Выгрузить() для ДанныеФормыКоллекция и как ее решить?

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

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

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

Причина 1: Контекстные ограничения типа ДанныеФормыКоллекция

Первое, что нам необходимо осознать: объект ДанныеФормыКоллекция — это не полноценная ТаблицаЗначений. Это специальный тип данных, предназначенный для оптимизированной работы интерфейса управляемой формы. Разберем технические нюансы:

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

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

Причина 2: Правило «Ближайшего контекста» в общих модулях

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

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

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

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

  1. Если вам необходимо, чтобы функции этого модуля ВСЕГДА выполнялись на сервере, снимите галочку «Клиент». Оставьте только «Сервер» и «Вызов сервера».
  2. В этом случае при вызове функции СоздатьДокументЯХПеремещениеНаОснованииСчета из клиентского кода формы, управление будет передано на сервер, и методы Выгрузить() и Загрузить() отработают корректно.

Пример корректной настройки общего модуля для работы с данными формы:

Решение 2: Использование метода КопироватьДанныеФормы

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

Разберем, как изменить код, чтобы он стал более универсальным:


// Вместо:
// ТЗЯХ = ДокументЯХ.Товары.Выгрузить();
// РезультатПодбора = НайтиЯХИсточники(ТЗРеализации, ТЗЯХ, ...);
// ДокументЯХ.Товары.Загрузить(ТЗЯХ);

// Мы можем использовать:
КопироватьДанныеФормы(ИсточникКоллекция, ДокументЯХ.Товары);

Метод КопироватьДанныеФормы работает эффективно, так как он копирует данные напрямую между структурами ДанныеФормы, не создавая тяжеловесных объектов ТаблицаЗначений в памяти. Однако помните, что если вам нужна сложная логика поиска или агрегации данных (как в функции НайтиЯХИсточники), этот метод может не подойти.

Решение 3: Преобразование данных формы в значения на сервере

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


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

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

Важные замечания по работе в обычном приложении

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

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

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

Итоговые рекомендации

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

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

← На главную