Как правильно сформировать запрос к табличной части справочника и выгрузить ее данные в XML в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При динамической выгрузке метаданных и данных справочников в формат XML разработчики часто сталкиваются с ситуацией, когда структура метаданных (имена реквизитов и табличных частей) успешно записывается в файл, а сами строки табличной части либо не выгружаются вовсе, либо вызывают синтаксические ошибки при выполнении запроса. Разберем по шагам, почему возникают такие проблемы и как их правильно исправить.

Анализ ошибок исходного кода

Выясним причину ошибок, которые привели к падению запроса и отсутствию данных в сформированном XML-файле:

  1. Неправильное имя таблицы в секции ИЗ. При обращении к табличной части справочника в языке запросов 1С используется составное имя с точкой: Справочник.<ИмяСправочника>.<ИмяТабличнойЧасти>. Если программно склеивать имя без разделителя, получится несуществующая таблица вида Справочник.СотрудникиТрудоваяДеятельность, что вызывает ошибку: «Таблица не найдена». Если же запрос строится к основной таблице справочника, платформа выдает исключение: «Поле не найдено», так как реквизиты табличной части не принадлежат шапке.
  2. Попытка вызова несуществующего метода Получить() у выборки. Объект ВыборкаИзРезультатаЗапроса не имеет метода Получить(Индекс), а его метод Количество() возвращает общее количество строк в выборке, а не число колонок. Обращение к элементам по числовому индексу внутри блока Попытка ... Исключение молча завершалось ошибкой, переменная оставалась равной Неопределено, и выгрузка данных попросту пропускалась.
  3. Жесткое ограничение типа. Условие Если Знч = Тип("Строка") Тогда игнорирует даты, числа, ссылки и булевы значения, отсекая значительную часть информации.
  4. Неверная контекстная переменная имени реквизита. Переменная Реквизит.Имя оставалась после завершения предыдущего цикла обхода метаданных, из-за чего атрибут XML получал некорректное имя последнего реквизита.

Корректное динамическое построение запроса к табличной части

Рассмотрим, как правильно сформировать текст запроса к каждой табличной части справочника. Имя таблицы должно обязательно содержать точку между именем справочника и именем табличной части. Также для связи со строками конкретного элемента следует выбирать поле Ссылка.

Посмотрим на пример правильного формирования запроса:


Для Каждого ТЧ Из Метаданные.Справочники.Сотрудники.ТабличныеЧасти Цикл

    ТекстПолей = "";
    Для Каждого Реквизит Из ТЧ.Реквизиты Цикл
        ТекстПолей = ТекстПолей + ", Справ." + Реквизит.Имя;
    КонецЦикла;

    ТекстЗапроса = 
        "ВЫБРАТЬ
        |   Справ.Ссылка КАК Ссылка,
        |   Справ.НомерСтроки КАК НомерСтроки" + ТекстПолей + "
        |ИЗ
        |   Справочник.Сотрудники." + ТЧ.Имя + " КАК Справ";

    Запрос = Новый Запрос;
    Запрос.Текст = ТекстЗапроса;
    РезультатЗапроса = Запрос.Выполнить();

КонецЦикла;

Правильный обход результатов и выгрузка в XML

Разберем, как получить значения полей из выборки. К полям выборки запроса можно обращаться по их строковым именам через оператор [], например Выборка[Реквизит.Имя].

Для преобразования любых типов данных платформы 1С (чисел, дат, ссылок, булево) в стандартный текстовый формат XML следует использовать глобальную функцию XMLСтрока(). Она корректно преобразует ссылки в GUID, даты в формат ISO (ГГГГ-ММ-ДД), а логические значения в true/false.

Объединим обход метаданных, выполнение запроса и сериализацию данных в единый рабочий пример:


ИмяСправочника = "Сотрудники";
ОбъектМетаданных = Метаданные.Справочники[ИмяСправочника];

Для Каждого ТЧ Из ОбъектМетаданных.ТабличныеЧасти Цикл

    Файл.ЗаписатьНачалоЭлемента("ТабличнаяЧасть");
    Файл.ЗаписатьАтрибут("Имя", ТЧ.Имя);
    Файл.ЗаписатьАтрибут("Синоним", ТЧ.Синоним);

    // 1. Формируем список полей выборки
    ТекстПолей = "";
    Для Каждого Реквизит Из ТЧ.Реквизиты Цикл
        ТекстПолей = ТекстПолей + ", Справ." + Реквизит.Имя + " КАК " + Реквизит.Имя;
    КонецЦикла;

    // 2. Формируем запрос с обязательной точкой перед именем ТЧ
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Справ.Ссылка.УникальныйИдентификатор КАК ИдентификаторЭлемента,
        |   Справ.НомерСтроки КАК НомерСтроки" + ТекстПолей + "
        |ИЗ
        |   Справочник." + ИмяСправочника + "." + ТЧ.Имя + " КАК Справ";

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    // 3. Обходим строки и реквизиты
    Пока Выборка.Следующий() Цикл
        Файл.ЗаписатьНачалоЭлемента("Строка");
        Файл.ЗаписатьАтрибут("НомерСтроки", XMLСтрока(Выборка.НомерСтроки));

        Для Каждого Реквизит Из ТЧ.Реквизиты Цикл
            Значение = Выборка[Реквизит.Имя];
            Если Значение <> Неопределено Тогда
                Файл.ЗаписатьНачалоЭлемента("Реквизит");
                Файл.ЗаписатьАтрибут("Имя", Реквизит.Имя);
                Файл.ЗаписатьАтрибут("Значение", XMLСтрока(Значение));
                Файл.ЗаписатьКонецЭлемента();
            КонецЕсли;
        КонецЦикла;

        Файл.ЗаписатьКонецЭлемента(); // Строка
    КонецЦикла;

    Файл.ЗаписатьКонецЭлемента(); // ТабличнаяЧасть

КонецЦикла;

Альтернативные способы выгрузки

Проанализируем другие стандартные механизмы 1С, которые позволяют избежать ручного формирования тегов XML:

  1. Использование метода ЗаписатьXML(). Если необходимо выгрузить объект целиком (шапку и все его табличные части), проще всего сериализовать объект платформенным методом:
    
    СправочникОбъект = ВыбраннаяСсылка.ПолучитьОбъект();
    ЗаписатьXML(Файл, СправочникОбъект, НазначениеТипаXML.Явное);
    
    Платформа автоматически сгенерирует правильную XML-структуру со всеми строками табличных частей и типами данных.
  2. Сериализация через СериализаторXDTO. Если табличную часть нужно выгрузить отдельно в виде таблицы значений:
    
    ТаблицаТЧ = ВыбраннаяСсылка.ТрудоваяДеятельность.Выгрузить();
    СериализаторXDTO.ЗаписатьXML(Файл, ТаблицаТЧ);
    
    Этот подход избавляет от необходимости писать динамические запросы и вручную перебирать колонки.
← На главную