При разработке во внешней обработке или в модуле управляемой формы программисты часто сталкиваются с ситуацией: в Синтакс-помощнике метод ВыгрузитьКолонку у объекта ТабличнаяЧасть описан, но при попытке вызвать его через Объект.ИмяТабличнойЧасти.ВыгрузитьКолонку() система выдает ошибку "Метод не обнаружен". В этой статье мы подробно разберем, почему так происходит, изучим архитектурные особенности платформы "1С:Предприятие 8.3" и рассмотрим несколько эффективных способов решения этой задачи.
Для начала проанализируем ситуацию, которая вводит в заблуждение многих разработчиков. Когда мы находимся в модуле управляемой формы, переменная Объект и её табличные части — это не те же самые объекты, с которыми мы работаем в модуле объекта (например, в коде проведения документа).
В управляемом интерфейсе данные на форме представлены специальными типами-декораторами. В частности, табличная часть на форме имеет тип ДанныеФормыКоллекция, а не ТабличнаяЧасть. Это сделано для оптимизации: данные формы должны быстро передаваться между клиентом и сервером, поэтому они лишены "тяжеловесных" методов прикладных объектов.
У типа ДанныеФормыКоллекция просто не существует метода ВыгрузитьКолонку. Именно поэтому контекстная подсказка его не показывает, а отладчик подтверждает отсутствие метода. Рассмотрим, как мы можем обойти это ограничение.
Самый простой и производительный способ получить данные из колонки на сервере — это предварительно выгрузить всю коллекцию в ТаблицуЗначений. У таблицы значений метод ВыгрузитьКолонку работает без нареканий.
Рассмотрим пример кода, который решает задачу автора темы:
// Код выполняется на сервере
// Выгружаем табличную часть "Возвраты" в таблицу значений
ТаблицаВозвратов = Объект.Возвраты.Выгрузить();
// Теперь у нас есть полноценная ТаблицаЗначений, и мы можем выгрузить колонку в массив
МассивДокументов = ТаблицаВозвратов.ВыгрузитьКолонку("Документ");
Этот подход хорош тем, что метод Выгрузить() у ДанныеФормыКоллекция работает очень быстро и создает в памяти копию данных в виде таблицы значений. После этого мы получаем доступ ко всему богатому функционалу этого типа, включая Свернуть, НайтиСтроки и интересующий нас ВыгрузитьКолонку.
Важное примечание: Метод Выгрузить() у данных формы доступен только на сервере. Попытка вызвать его на клиенте приведет к ошибке.
Если нам нужно не просто получить массив, а выполнить сложные манипуляции с объектом, используя его "родные" методы табличных частей, мы можем временно преобразовать данные формы в настоящий прикладной объект (например, в объект обработки или документа).
Разберем, как это работает на сервере:
// Преобразуем данные формы (Объект) в реальный объект обработки
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Теперь ОбработкаОбъект.Возвраты имеет тип "ТабличнаяЧасть"
// И метод ВыгрузитьКолонку становится доступен
МассивДокументов = ОбработкаОбъект.Возвраты.ВыгрузитьКолонку("Документ");
Проанализируем этот способ. Несмотря на свою элегантность, он имеет существенный минус — производительность. Метод РеквизитФормыВЗначение заставляет платформу полностью инициализировать объект, заполнить все его реквизиты, а для документов — еще и подготовить дополнительные структуры. Если табличная часть содержит тысячи строк, этот метод отработает значительно медленнее, чем простое Выгрузить().
Иногда нам требуется получить массив данных на стороне клиента или когда мы не хотим плодить лишние объекты в памяти. В этом случае мы можем воспользоваться простым перебором коллекции. Хотя это выглядит как "изощрение", на небольших объемах данных это работает мгновенно и прозрачно.
МассивДокументов = Новый Массив;
// Этот цикл работает и на клиенте, и на сервере
Для Каждого СтрокаВозврата Из Объект.Возвраты Цикл
МассивДокументов.Добавить(СтрокаВозврата.Документ);
КонецЦикла;
Преимущество этого метода в том, что он работает в любом контексте и не требует серверных вызовов, если данные уже находятся на клиенте (и нам нужно сформировать массив для клиентской логики).
Если данные в табличной части уже записаны (например, мы работаем в форме существующего документа), зачастую правильнее вообще не обращаться к реквизитам формы. Рассмотрим ситуацию: нам нужно получить список документов из табличной части, чтобы выполнить по ним какую-то проверку.
Вместо того чтобы тянуть данные из формы на сервер, выгружать их и преобразовывать, мы можем написать быстрый запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Возвраты.Документ КАК Документ
|ИЗ
| Документ.НазваниеВашегоДокумента.Возвраты КАК Возвраты
|ГДЕ
| Возвраты.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
// Выгружаем результат запроса сразу в массив
МассивДокументов = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Документ");
Этот способ является наиболее предпочтительным с точки зрения стандартов разработки "1С", если данных много и они хранятся в базе данных. Это исключает передачу лишнего контекста формы.
Подведем итог и выясним, какой метод выбрать в зависимости от ситуации:
Таким образом, отсутствие метода ВыгрузитьКолонку у табличной части на форме — это не ошибка платформы, а особенность работы с типом ДанныеФормыКоллекция. Понимая разницу между данными формы и прикладными объектами, вы сможете писать более эффективный и надежный код.