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