В процессе разработки интеграционных механизмов, в частности Web-сервисов для обмена данными между базами 1С (например, БП КОРП и внешними системами), мы часто сталкиваемся с неочевидными ошибками. Одна из таких ситуаций — возникновение ошибки **"Поле не найдено"** после безобидного, на первый взгляд, изменения имени поля (псевдонима) в тексте запроса. Давайте подробно разберем ситуацию, с которой столкнулся разработчик при переходе с COM-соединения на Web-сервисы, проанализируем причины поведения платформы и сформулируем правила написания устойчивого кода.
Представим ситуацию: мы пишем код внутри модуля Web-сервиса, расположенного в расширении конфигурации. Наша задача — выбрать данные из документа ОтчетКомиссионераОПродажах.
Изначальный текст запроса выглядит корректно и выполняется без ошибок:
Запрос.Текст =
"ВЫБРАТЬ
| ОтчетКомиссионераОПродажахТовары.Ссылка.Дата КАК Дата,
| ОтчетКомиссионераОПродажахТовары.Ссылка.Номер КАК Номер,
// ... другие поля ...
|ИЗ
| Документ.ОтчетКомиссионераОПродажах.Товары КАК ОтчетКомиссионераОПродажахТовары
|ГДЕ
| ОтчетКомиссионераОПродажахТовары.Ссылка.Дата МЕЖДУ &Дата1 И &Дата2
|УПОРЯДОЧИТЬ ПО
| Дата,
| Номер";
Однако, как только мы решаем изменить имя выходного поля (псевдоним) для удобства дальнейшей сериализации или соответствия требованиям XDTO-пакета, возникает проблема. Например, меняем Дата на ДатаДок:
// Изменили только псевдоним в секции ВЫБРАТЬ
ОтчетКомиссионераОПродажахТовары.Ссылка.Дата КАК ДатаДок,
При выполнении этого кода Web-сервис возвращает ошибку SOAP Fault с кодом Client:
{(20, 2)}: Поле не найдено "Дата" <>>Дата.
У многих разработчиков возникает резонный вопрос: почему изменение имени поля в одном месте ломает запрос, и почему платформа "не видит" исходное поле?
Чтобы понять причину, нам нужно углубиться в то, как платформа 1С интерпретирует язык запросов. Ключевой момент здесь — область видимости имен полей в различных секциях запроса.
Разберем структуру запроса по порядку выполнения платформой (логически):
1. **Источник данных (ИЗ):** Сначала платформа определяет, откуда брать данные. Здесь мы обращаемся к табличной части документа.
2. **Фильтрация (ГДЕ):** Затем накладываются условия. Обратите внимание: в секции ГДЕ мы **не можем** использовать псевдонимы, заданные в секции ВЫБРАТЬ. Здесь мы оперируем только реальными полями таблиц базы данных (например, ОтчетКомиссионераОПродажахТовары.Ссылка.Дата).
3. **Выборка (ВЫБРАТЬ):** На этом этапе формируется результирующая таблица. Именно здесь мы задаем псевдонимы (алиасы). Если мы написали ... КАК ДатаДок, то в итоговой выборке колонка будет называться именно ДатаДок. Имя Дата перестает существовать для результирующего набора.
4. **Сортировка (УПОРЯДОЧИТЬ ПО):** Это финальный этап. Сортировка применяется уже к сформированному результату выборки. Следовательно, эта секция оперирует именами полей, которые получились после этапа ВЫБРАТЬ.
**В чем заключалась ошибка?**
Разработчик изменил псевдоним в начале запроса:
ОтчетКомиссионераОПродажахТовары.Ссылка.Дата КАК ДатаДок
Но оставил старое имя в конце запроса:
УПОРЯДОЧИТЬ ПО
Дата, // Ошибка! Этого поля больше нет в результате выборки
Номер
Платформа пытается найти колонку Дата в результатах выборки, чтобы отсортировать по ней таблицу, но находит только колонку ДатаДок. Отсюда и возникает ошибка "Поле не найдено".
Чтобы исправить ошибку, необходимо синхронизировать имена полей в секции выборки и в секции сортировки. Если вы переименовываете поле в ВЫБРАТЬ, обязательно проверьте секции УПОРЯДОЧИТЬ ПО и ИТОГИ.
**Правильный вариант кода:**
Запрос.Текст =
"ВЫБРАТЬ
| ОтчетКомиссионераОПродажахТовары.Ссылка.Дата КАК ДатаДок, // Псевдоним изменен
| ОтчетКомиссионераОПродажахТовары.Ссылка.Номер КАК Номер,
| // ... остальные поля ...
|ИЗ
| Документ.ОтчетКомиссионераОПродажах.Товары КАК ОтчетКомиссионераОПродажахТовары
|ГДЕ
| // В ГДЕ используем обращение через точку к полям базы данных
| ОтчетКомиссионераОПродажахТовары.Ссылка.Дата МЕЖДУ &Дата1 И &Дата2
|УПОРЯДОЧИТЬ ПО
| ДатаДок, // Используем НОВЫЙ псевдоним
| Номер";
Автор темы упомянул, что потратил пару часов на поиск этой зависимости, так как ошибка приходила через Web-сервис. Отладка SOAP-запросов действительно сложнее, чем отладка обычного кода в форме, так как вы часто видите лишь общее сообщение "Internal Server Error" или "Client Fault".
Рассмотрим несколько советов, которые помогут быстрее находить подобные ошибки:
1. **Используйте Конструктор запроса.**
Даже если запрос сложный, старайтесь загонять его в Конструктор запроса (ПКМ -> Конструктор запроса). При переименовании поля на вкладке "Поля", конструктор **автоматически** обновит имя этого поля на вкладке "Порядок" (сортировка) и "Итоги". Это исключает человеческий фактор.
*Примечание: Если запрос содержит специфичные конструкции, которые конструктор не может разобрать, копируйте его части во внешнюю консоль запросов.*
2. **Тестируйте код во внешней обработке.**
Перед тем как публиковать Web-сервис, вынесите логику формирования запроса и получения данных в отдельный Общий Модуль или временную внешнюю обработку. Запустите этот код в режиме "1С:Предприятие". В этом случае вы сразу увидите понятное окно ошибки с указанием строки кода, а не абстрактный XML-ответ.
3. **Анализируйте Журнал регистрации.**
Даже если клиентская часть получает невнятную ошибку SOAP, сервер 1С обычно пишет полный стек ошибки в Журнал регистрации. Там можно увидеть конкретное описание: {(20, 2)}: Поле не найдено "Дата".
4. **Специфика перехода с COM на Web-сервисы.**
Переход с COM на WS — правильный шаг с точки зрения архитектуры. COM-соединение держит сеанс, потребляет много памяти и работает только под Windows. Web-сервисы работают в режиме "запрос-ответ" (stateless) и кроссплатформенны. Однако WS требуют строгой типизации.
В запросе автора используется УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Ссылка). Это отличная практика для Web-сервисов. Передавать ссылочные типы (СправочникСсылка, ДокументСсылка) через XML/JSON ненадежно, так как во внешней системе этих объектов может не быть. Передача строкового представления (Наименования) и GUID (Уникального Идентификатора) — стандарт надежной интеграции.
Ошибка "Поле не найдено" при наличии поля в базе данных почти всегда указывает на рассинхронизацию псевдонимов в запросе.
* В секции ВЫБРАТЬ мы создаем новые имена (псевдонимы).
* В секции ГДЕ мы обязаны использовать оригинальные пути к данным (Таблица.Поле).
* В секции УПОРЯДОЧИТЬ ПО мы должны использовать псевдонимы, созданные в ВЫБРАТЬ.
Будьте внимательны при ручном редактировании текста запроса и по возможности пользуйтесь инструментами автоматизации (Конструктором запроса), чтобы избежать потери времени на поиск простых синтаксических ошибок.