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