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