Ошибка «Таблица не найдена» при обращении к константам через OData REST-интерфейс: разбираем причины и ищем решение

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При активном внедрении интеграционных механизмов в СУБД-экосистему платформы «1С:Предприятие» разработчики часто выбирают стандартный REST-интерфейс OData. Он позволяет быстро и без написания кода получить доступ к метаданным конфигурации. Однако при работе со старыми конфигурациями (например, находящимися на режиме совместимости 8.3.4, 8.2 или ниже) можно столкнуться с крайне неочевидной ошибкой при попытке прочитать значение любой константы.

Запрос вида http://host/base/odata/standard.odata/Constant_ИмяКонстанты?$format=json внезапно возвращает ошибку СУБД:


{
  "odata.error": {
    "code": "-1",
    "message": {
      "lang": "ru",
      "value": "{(1, 30)}: Таблица не найдена \"Constant.ИмяКонстанты\"\nSELECT sourceAlias.* FROM <<?>>Constant.ИмяКонстанты AS sourceAlias"
    }
  }
}

При этом обращение к справочникам или документам по аналогичным адресам работает абсолютно корректно и стабильно. В рамках этой статьи мы подробно разберем, почему возникает данная проблема, как особенности хранения данных в СУБД влияют на поведение OData и какими способами можно обойти это платформенное ограничение.

В чем причина ошибки: заглянем под капот СУБД и платформы

Чтобы понять природу этой ошибки, проанализируем эволюцию архитектуры платформы 1С. Ключевой фактор здесь — это физическая структура хранения констант в базе данных на уровне СУБД (MS SQL Server, PostgreSQL и др.):

  1. До версии платформы 8.2.14: все константы, определенные в конфигурации, физически хранились в базе данных в одной единственной таблице (обычно она называется _Consts). Каждая константа представляла собой отдельную колонку (поле) внутри этой общей таблицы.
  2. Начиная с версии платформы 8.2.14: разработчики 1С изменили этот подход в целях повышения производительности и снижения блокировок базы данных при одновременной записи разных констант. С этого момента для каждой константы СУБД создает свою собственную отдельную таблицу (например, _Const1234).

Однако то, какая именно структура хранения будет использоваться в вашей базе данных, напрямую зависит от настройки «Режим совместимости» в свойствах конфигурации:

Интерфейс OData (стандартный REST-интерфейс 1С) проектировался и оптимизировался под новые стандарты платформы. При обработке запроса к ресурсу Constant_ИмяКонстанты транслятор OData генерирует низкоуровневый SQL-запрос, ориентируясь на современную схему данных. Он пытается обратиться к таблице Constant.ИмяКонстанты, ожидая, что она существует отдельно. Но поскольку база данных работает в старом режиме совместимости, СУБД возвращает закономерный ответ: «Таблица не найдена».

При этом в XML-описании метаданных по адресу .../odata/standard.odata/$metadata константа будет отображаться как существующий тип данных. Происходит это потому, что генератор метаданных анализирует логическую структуру конфигурации, а СУБД-исполнитель пытается выполнить запрос физически.

Рассмотрим подробнее три практических метода решения этой проблемы, начиная от кардинального изменения настроек системы и заканчивая программными обходными путями.

---

Решение №1. Повышение режима совместимости конфигурации

Самый очевидный способ решить проблему «в лоб» — обновить режим совместимости конфигурации до актуального (или как минимум до значения 8.3.5). Это заставит платформу реструктуризировать базу данных и выделить для каждой константы индивидуальную таблицу.

Также повышение режима совместимости до 8.3.5 откроет вам доступ к встроенной функции управления составом OData:


тМассив = Новый Массив;
тМассив.Добавить(Метаданные.Константы.ДатаНачалаАвтоматическогоОтраженияВУчетеНДС);
УстановитьСоставСтандартногоИнтерфейсаOData(тМассив);

В режимах совместимости 8.3.4 и ниже попытка выполнить этот код вызовет ошибку, сообщающую, что метод УстановитьСоставСтандартногоИнтерфейсаOData недоступен.

Важное предупреждение: переход на новый режим совместимости для старых и сильно доработанных конфигураций (таких как БП 2.0 КОРП или УПП 1.3) сопряжен с огромными рисками. В платформе версии 8.3.5 были изменены правила выполнения серверных вызовов при закрытии форм, изменены некоторые механизмы блокировок и удалены устаревшие функции. Изменение режима совместимости потребует от вас тотального тестирования всей конфигурации и исправления множества сопутствующих ошибок в коде.

---

Решение №2. Использование собственного HTTP-сервиса (Рекомендуемый метод)

Если менять режим совместимости всей информационной базы категорически запрещено из соображений стабильности, наилучшим решением будет отказаться от OData для чтения констант и разработать собственный простой HTTP-сервис.

Давайте разберем по шагам, как быстро реализовать такой сервис в конфигураторе:

  1. В дереве метаданных перейдите в ветку Общие -> HTTP-сервисы и добавьте новый сервис (например, ПолучениеДанных).
  2. Укажите корневой шаблон (например, /v1).
  3. Добавьте шаблон URL с именем GetConstant и шаблоном пути /constants/{ИмяКонстанты}.
  4. Для этого шаблона создайте метод GET и назначьте ему обработчик в модуле HTTP-сервиса.

Ниже представлен универсальный пример программного кода для чтения констант через ваш новый HTTP-сервис:


Функция ПолучитьКонстантуGET(Запрос)
	
	ИмяКонстанты = Запрос.ПараметрыURL.Получить("ИмяКонстанты");
	
	// Проверяем наличие константы в метаданных для защиты от некорректных запросов
	МетаданноеКонстанты = Метаданные.Константы.Найти(ИмяКонстанты);
	Если МетаданноеКонстанты = Неопределено Тогда
		Ответ = Новый HTTPСервисОтвет(404);
		Ответ.УстановитьТелоИзСтроки("Константа '" + ИмяКонстанты + "' не найдена в метаданных.");
		Возврат Ответ;
	КонецЕсли;
	
	// Получаем значение константы динамически
	ЗначениеКонстанты = Константы[ИмяКонстанты].Получить();
	
	// Формируем структуру ответа в формате JSON
	СтруктураОтвета = Новый Структура;
	СтруктураОтвета.Вставить("Name", ИмяКонстанты);
	СтруктураОтвета.Вставить("Value", ЗначениеКонстанты);
	
	// Сериализуем данные в строку JSON
	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.УстановитьСтроку();
	ЗаписатьJSON(ЗаписьJSON, СтруктураОтвета);
	СтрокаJSON = ЗаписьJSON.Закрыть();
	
	// Формируем успешный HTTP-ответ
	Ответ = Новый HTTPСервисОтвет(200);
	Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
	Ответ.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
	
	Возврат Ответ;
	
КонецФункции

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

---

Решение №3. Синхронизация значений констант через Регистр Сведений

Если внешняя система жестко завязана именно на протокол OData и не может быть перенастроена на работу с другими HTTP-адресами, мы можем прибегнуть к архитектурному обходу проблемы внутри 1С. Для этого мы будем дублировать значения нужных констант в специально созданный Регистр Сведений, к которому OData сможет обращаться без каких-либо ошибок.

Проанализируем по шагам процесс реализации этого обходного пути:

  1. Создайте новый непериодический независимый Регистр Сведений с именем БуферКонстант.
  2. Добавьте измерение ИмяКонстанты (тип: Строка, длина 150, индексировать).
  3. Добавьте ресурс Значение (тип: ЛюбаяСсылка, Число, Строка, Дата, Булево — настройте составной тип данных в зависимости от типов ваших констант).
  4. Включите данный регистр сведений в состав стандартного интерфейса OData (если состав настраивается программно в вашей версии платформы).

Теперь нам необходимо обеспечить актуальность данных в этом регистре. Для этого мы напишем подписку на событие или внесем изменения непосредственно в модуль менеджера константы. Поскольку константы меняются нечасто, этот код не создаст никакой нагрузки на систему.

Пример кода для записи значения константы в наш регистр-буфер:


Процедура ЗаписатьКонстантуВБуфер(ИмяКонстанты, ЗначениеКонстанты) Экспорт
	
	МенеджерЗаписи = РегистрыСведений.БуферКонстант.СоздатьМенеджерЗаписи();
	МенеджерЗаписи.ИмяКонстанты = ИмяКонстанты;
	
	// Считываем текущую запись, чтобы не перезаписывать данные без необходимости
	МенеджерЗаписи.Прочитать();
	Если Не МенеджерЗаписи.Выбран() Или МенеджерЗаписи.Значение <> ЗначениеКонстанты Тогда
		МенеджерЗаписи.ИмяКонстанты = ИмяКонстанты;
		МенеджерЗаписи.Значение = ЗначениеКонстанты;
		МенеджерЗаписи.Записать(Истина);
	КонецЕсли;
	
КонецПроцедуры

Этот метод регистрации изменений позволит вам получать актуальные данные констант через стандартный REST-запрос OData к регистру сведений:

http://host/base/odata/standard.odata/InformationRegister_БуферКонстант(ИмяКонстанты='ДатаНачалаАвтоматическогоОтраженияВУчетеНДС')?$format=json

Резюме

Мы выяснили истинную причину ошибки — конфликт между ожидаемой физической структурой OData и реальным устройством таблиц СУБД в режиме совместимости 8.3.4 и ниже. Для решения этой проблемы вы можете выбрать любой из предложенных вариантов в зависимости от жесткости требований к стабильности вашей конфигурации 1С. Использование собственного HTTP-сервиса видится наиболее надежным и современным подходом, исключающим необходимость внесения опасных изменений в свойства совместимости конфигурации.

← На главную