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