При переходе на новые релизы конфигураций 1С:Управление торговлей 11.5, 1С:ERP 2.5 или Комплексная автоматизация 2.5 (начиная с ветки 11.5.17 / 2.5.17 и выше) администраторы и программисты часто сталкиваются с «фантомной» ошибкой. Проблема проявляется при проведении документов или расчете скидок в заказе клиента или реализации. Система выдает сообщение об ошибке во время выполнения встроенного языка: Таблица не найдена "Константа.ИспользоватьПроизводительныйРежимЗаписиИнформацииОДоступностиТоваровИРабот".
Особенность этой ситуации в том, что глобальный поиск по конфигурации не находит обращений к этой константе в текстах модулей или макетов. В данной статье мы разберем причины возникновения этой ошибки и рассмотрим способы её полного устранения.
Проанализируем архитектурные изменения в последних релизах. В рамках оптимизации механизмов учета резервов и доступности товаров разработчики фирмы «1С» окончательно удалили константу ИспользоватьПроизводительныйРежимЗаписиИнформацииОДоступностиТоваровИРабот. Теперь «производительный режим» является единственно возможным и обязательным, поэтому настройка стала избыточной.
Однако подсистема Скидки (наценки) в целях повышения производительности использует механизм кэширования текстов запросов. Когда вы создаете условие предоставления скидки, система на основе настроек компоновки данных (СКД) генерирует текст запроса и сохраняет его в базе данных. Местом хранения является справочник УсловияПредоставленияСкидокНаценок, а именно реквизит ХранилищеНастроекКомпоновкиДанных, имеющий тип ХранилищеЗначения.
Если в момент обновления информационной базы (ИБ) штатные процедуры отложенного обновления не смогли обработать какой-то элемент справочника (например, из-за блокировки объекта пользователем), в хранилище остается старый текст запроса, содержащий обращение к уже удаленной из метаданных константе. Именно поэтому поиск по конфигуратору ничего не дает — «битый» код находится внутри данных в SQL-таблице.
Прежде чем переходить к программным методам, нам необходимо убедиться, что все стандартные процедуры обновления завершены успешно. Рассмотрим порядок действий:
УсловияПредоставленияСкидокНаценок или подсистемой скидок, запустим их выполнение вручную.Если система рапортует о том, что все обновления выполнены, но ошибка сохраняется, значит, произошел сбой логики, и нам потребуется вмешательство в данные.
Рассмотрим наиболее эффективный способ решения проблемы — программный перебор справочника и принудительное обновление кэшированных запросов. Для этого мы можем воспользоваться встроенным методом типового решения СкидкиНаценкиСервер.ОбновитьКэшированныйЗапрос(). Разберем пример кода, который можно запустить во внешней обработке:
Процедура ИсправитьФантомныйЗапрос() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Условия.Ссылка КАК Ссылка
|ИЗ
| Справочник.УсловияПредоставленияСкидокНаценок КАК Условия";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
СправочникОбъект = Выборка.Ссылка.ПолучитьОбъект();
НастройкиКомпоновки = СправочникОбъект.ХранилищеНастроекКомпоновкиДанных.Получить();
// Проверяем наличие структуры настроек и текста запроса в ней
Если ТипЗнч(НастройкиКомпоновки) = Тип("Структура") И НастройкиКомпоновки.Свойство("Запрос") Тогда
СтруктураЗапроса = НастройкиКомпоновки.Запрос;
Если ТипЗнч(СтруктураЗапроса) = Тип("Структура") И СтруктураЗапроса.Свойство("ТекстЗапроса") Тогда
ТекстЗапроса = СтруктураЗапроса.ТекстЗапроса;
// Ищем упоминание удаленной константы
Если СтрНайти(ТекстЗапроса, "ИспользоватьПроизводительныйРежимЗаписиИнформацииОДоступностиТоваровИРабот") > 0 Тогда
Попытка
// Вызываем штатный метод обновления кэша
СкидкиНаценкиСервер.ОбновитьКэшированныйЗапрос(СправочникОбъект);
СправочникОбъект.Записать();
Сообщить("Обновлен кэш для: " + СправочникОбъект.Наименование);
Исключение
Сообщить("Ошибка при обработке " + СправочникОбъект.Наименование + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем, что именно происходит при вызове метода ОбновитьКэшированныйЗапрос(). Система заново обращается к схеме компоновки данных, определенной для данного условия предоставления скидки, и генерирует свежий текст SQL-запроса. Поскольку в актуальной версии метаданных Константа.ИспользоватьПроизводительныйРежимЗаписиИнформацииОДоступностиТоваровИРабот отсутствует, генератор запросов 1С исключает её из финального текста, и ошибка исчезает.
Также стоит обратить внимание на типовую процедуру обновления, которая могла не отработать корректно. Посмотрим на фрагмент кода из общего модуля УсловияПредоставленияСкидокНаценок:
Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт
// ... блокировка данных и получение объекта ...
НастройкиКомпоновкиДанных = СправочникОбъект.ХранилищеНастроекКомпоновкиДанных.Получить();
Если ЗначениеЗаполнено(НастройкиКомпоновкиДанных)
И СтрНайти(НастройкиКомпоновкиДанных.Запрос.ТекстЗапроса, "ИспользоватьПроизводительныйРежимЗаписиИнформацииОДоступностиТоваровИРабот") > 0 Тогда
СкидкиНаценкиСервер.ОбновитьКэшированныйЗапрос(СправочникОбъект);
СправочникОбъект.УдалитьОбновленНаПроизводительныйРежим = Истина;
ОбновлениеИнформационнойБазы.ЗаписатьОбъект(СправочникОбъект);
КонецЕсли;
// ...
КонецПроцедуры
Важный момент: Если вы используете расширения конфигурации, проверьте, не переопределяют ли они поведение справочника УсловияПредоставленияСкидокНаценок или общих модулей подсистемы скидок. В некоторых случаях расширение может блокировать выполнение типовых обработчиков обновления.
Если проблемных элементов в справочнике немного, можно обойтись без написания кода. Для этого выполним следующие действия:
ПередЗаписью или ПриЗаписи, который зачастую инициирует обновление кэша настроек, если они были изменены или требуют актуализации.Однако программный метод, описанный выше, является более надежным, так как он гарантированно проверяет внутреннее содержимое ХранилищаЗначения во всех элементах справочника, включая помеченные на удаление или неактивные.
В редких случаях после очистки данных на уровне объектов 1С ошибка может сохраняться на уровне планов выполнения SQL. Если ваша база работает на MS SQL Server, и после программного обновления кэша справочников ошибка воспроизводится, попробуйте выполнить команду очистки процедурного кэша в консоли SQL Management Studio:
DBCC FREEPROCCACHE
Это заставит сервер базы данных пересобрать планы выполнения запросов и окончательно избавит систему от ссылок на несуществующие таблицы констант.
Подводя итог, отметим, что проблема «фантомного кода» — это классическое следствие оптимизации метаданных при сохранении старых кэшированных данных. Своевременный контроль завершения отложенных обновлений и использование штатных методов актуализации запросов позволяют решить эту задачу без существенных трудозатрат.