К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как обойти ограничения ДанныеФормыКоллекция в 1С

ДанныеФормыКоллекция в 1С не поддерживает сортировку, поиск и передачу на сервер. Разбираем рабочие способы обойти ограничения через таблицы значений и запросы.

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

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

Ниже разобраны конкретные сценарии с готовыми фрагментами кода, которые можно переносить в свою конфигурацию практически без изменений.

Почему ДанныеФормыКоллекция ведёт себя не как таблица значений

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

Доступные у коллекции методы ограничены: Добавить(), Вставить(), Удалить(), Очистить(), Количество(), Индекс(), Сдвинуть(), НайтиПоИдентификатору(), а также Выгрузить() и Загрузить() — но только в серверном контексте. Всё остальное придётся эмулировать.

Универсальный приём: Выгрузить() → обработать → Загрузить()

Самый надёжный способ обойти ограничения — на сервере выгрузить коллекцию в обычную таблицу значений, выполнить с ней любые операции и загрузить результат обратно. Методы Выгрузить() и Загрузить() доступны только в серверном контексте, поэтому клиентская процедура должна вызывать серверную.

Типовой шаблон выглядит так:

&НаСервере

Процедура СортироватьТаблицуНаСервере()

ТЗ = Объект.Товары.Выгрузить();

ТЗ.Сортировать("Номенклатура Возр");

Объект.Товары.Загрузить(ТЗ);

КонецПроцедуры

&НаКлиенте

Процедура СортироватьТаблицу(Команда)

СортироватьТаблицуНаСервере();

КонецПроцедуры

Для табличной части объекта (Объект.Товары) вызов сервера можно избежать через директиву &НаКлиенте с обращением к данным объекта — но сама выгрузка всё равно требует серверного контекста. Если таблица является реквизитом формы, а не табличной частью, обращайтесь через ЭтаФорма.ИмяРеквизита.

Порядок действий для обработки коллекции
  1. 1
    Создайте серверную процедуру с директивой &НаСервере
  2. 2
    Выгрузите коллекцию: ТЗ = РеквизитФормы.Выгрузить()
  3. 3
    Выполните нужные операции: Сортировать(), НайтиСтроки(), Свернуть(), запрос
  4. 4
    Загрузите результат обратно: РеквизитФормы.Загрузить(ТЗ)
  5. 5
    Вызовите серверную процедуру из клиентской и проверьте отображение в форме

Поиск строк без метода Найти()

На клиенте метод Найти() недоступен, поэтому поиск выполняется перебором строк в цикле. Для небольших таблиц (сотни строк) это работает мгновенно и не требует серверного вызова:

&НаКлиенте

Функция НайтиСтрокуПоНоменклатуре(ИскомаяНоменклатура)

Для Каждого Строка Из Объект.Товары Цикл

Если Строка.Номенклатура = ИскомаяНоменклатура Тогда

Возврат Строка;

КонецЕсли;

КонецЦикла;

Возврат Неопределено;

КонецФункции

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

Использование данных коллекции в запросе

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

&НаСервере

Функция ПолучитьЦеныНаСервере()

ТЗ = Объект.Товары.Выгрузить(, "Номенклатура,Количество");

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ Т.Номенклатура, Т.Количество

|ПОМЕСТИТЬ ВТ ИЗ &ТЗ КАК Т

|;

|ВЫБРАТЬ ...";

Запрос.УстановитьПараметр("ТЗ", ТЗ);

...

КонецФункции

Обратите внимание на второй параметр Выгрузить() — список колонок. Выгружая только нужные колонки, вы сокращаете объём данных и упрощаете временную таблицу в запросе.

Сортировка и свёртка: варианты в зависимости от объёма

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

Свёртка (группировка с суммированием) аналогично выполняется только после выгрузки: ТЗ.Свернуть("Номенклатура", "Количество,Сумма"). Если свёртка нужна только для показа итогов пользователю, а исходные строки должны остаться — загружайте результат в отдельный реквизит формы, а не поверх основной коллекции.

Способы обхода ограничений

Выгрузить/Загрузить в ТЗ

Универсальный вариант для сортировки, свёртки, запросов. Требует серверного вызова, при больших таблицах — заметные затраты на копирование.

Перебор строк в цикле

Работает на клиенте без сервера. Подходит для поиска и подсчётов на небольших таблицах, медленно на тысячах строк.

Динамический список с произвольным запросом

Сортировка, отбор и группировка средствами СКД/запроса без ручной обработки. Не подходит, если пользователь редактирует строки вручную.

Временный реквизит-таблица + запрос

Для сложной аналитики: выгрузка во временную таблицу и вся логика в запросе. Требует аккуратности с типами колонок.

Передача таблицы между клиентом и сервером

Напрямую передать ДанныеФормыКоллекция или таблицу значений параметром клиент-серверного вызова нельзя — таблица значений не сериализуется. Обходные пути:

  • работать с реквизитом формы: он автоматически доступен и на клиенте, и на сервере, отдельная передача не нужна;
  • упаковать данные в массив структур и передать его — структуры и массивы сериализуются;
  • для больших объёмов — поместить таблицу во временное хранилище на сервере через ПоместитьВоВременноеХранилище() и передавать только адрес.

Вариант с массивом структур удобен, когда данные формируются на клиенте (например, результат сканирования ШК) и их нужно обработать на сервере без привязки к реквизиту формы.

Типичные ошибки и проверка результата

Чаще всего проблемы возникают не из-за самих ограничений коллекции, а из-за неверного контекста выполнения или потери связи строк с элементами формы. После Загрузить() идентификаторы строк пересоздаются, поэтому сохранённые ранее значения ПолучитьИдентификатор() перестают быть актуальными — текущую строку нужно искать заново.

Ещё одна частая ошибка — обращение к реквизиту формы как к таблице значений в модуле объекта. В модуле объекта табличная часть — это настоящая таблица значений, а в модуле формы — ДанныеФормыКоллекция. Код, перенесённый из модуля объекта в форму без адаптации, почти гарантированно упадёт.

Типичные ошибки
01
Вызов Выгрузить() в клиентской процедуре — ошибка «Метод объекта не обнаружен», переносите выгрузку на сервер
02
Использование старых идентификаторов строк после Загрузить() — идентификаторы пересоздаются, текущую строку нужно находить заново
03
Серверный вызов внутри цикла по строкам — резкое падение производительности, собирайте данные и обрабатывайте одним вызовом
04
Передача таблицы значений параметром между клиентом и сервером — не сериализуется, используйте массив структур или временное хранилище
05
Загрузка результата поверх редактируемой таблицы без необходимости — пользователь теряет несохранённые правки строк
Контрольные точки

Как проверить результат

Отображение таблицы после Загрузить()
Норма

Строки видны в форме в новом порядке, данные без искажений

Тревожный признак

Таблица пустая или порядок не изменился — проверьте, что загружали именно обработанную ТЗ

Текущая строка после обработки
Норма

Активная строка установлена программно через Элементы.Таблица.ТекущаяСтрока

Тревожный признак

Курсор «слетел», обращение по старому идентификатору даёт ошибку

Производительность
Норма

Форма реагирует мгновенно, один серверный вызов на операцию

Тревожный признак

Заметные паузы — ищите серверные вызовы внутри цикла

FAQ

Можно ли отсортировать ДанныеФормыКоллекция без серверного вызова?

Нет, метод Сортировать() недоступен ни в одном контексте у этого объекта. Без сервера остаётся только ручная перестановка строк через Сдвинуть() с собственным алгоритмом сортировки, что оправдано лишь для очень маленьких таблиц. Практичнее один серверный вызов с Выгрузить/Сортировать/Загрузить.

Почему НайтиСтроки() не работает с реквизитом формы?

Метод НайтиСтроки() принадлежит таблице значений, а реквизит формы в модуле формы представлен объектом ДанныеФормыКоллекция. Сначала выполните Выгрузить() на сервере, затем ищите в полученной таблице значений.

Как добавить строку в коллекцию на клиенте?

Метод Добавить() доступен и на клиенте: НоваяСтрока = Объект.Товары.Добавить(); затем заполните поля строки. Это одна из немногих операций, не требующих обходных приёмов.

Чем отличается работа с табличной частью документа и с реквизитом формы типа ТаблицаЗначений?

В модуле формы оба представлены как ДанныеФормыКоллекция, ограничения одинаковые. Разница в том, что табличная часть доступна и в модуле объекта как полноценная таблица значений — часть логики можно вынести туда, где все методы работают.

Как передать содержимое таблицы в другую форму?

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

Почему после Загрузить() перестала работать установка текущей строки?

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

Итог

Что важно запомнить

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