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