При разработке расширений для конфигураций на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда проверенный запрос, идеально работающий в основной конфигурации, внезапно выдает ошибку при переносе в расширение. Особенно часто это происходит в динамических списках, использующих сложные соединения со справочниками и виртуальными таблицами регистров. Проанализируем одну из таких критических ошибок: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов».
Рассмотрим ситуацию: мы создаем расширение для обработки «Подбор номенклатуры» и модифицируем запрос динамического списка. В запросе выполняется левое соединение справочника Номенклатура с виртуальной таблицей СрезПоследних регистра сведений ЦеныНоменклатуры. Несмотря на то, что типы полей в метаданных определены четко, платформа выдает ошибку сравнения типов в секции ПО (условие связи).
Выясним причину такого поведения. Это явление связано с особенностями работы механизма макетирования запросов в расширениях. На определенных релизах платформы (особенно веток 8.3.23 и ранних 8.3.24) при обращении к объектам, добавленным в расширение, система может «терять» жесткую типизацию поля Ссылка. Вместо конкретного типа СправочникСсылка.Номенклатура, платформа может интерпретировать поле как обобщенный ссылочный тип. При попытке сопоставить такой «размытый» тип с четко типизированным измерением регистра во время выполнения SQL-запроса возникает конфликт, который система интерпретирует как сравнение несовместимых типов.
Самый быстрый и надежный способ обойти данную проблему без обновления платформы — использование оператора ВЫРАЗИТЬ непосредственно в условии соединения таблиц. Разберем по шагам, как модифицировать запрос.
Предположим, наш исходный (проблемный) фрагмент кода выглядит так:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ...) КАК Цены
ПО СправочникНоменклатура.Ссылка = Цены.Номенклатура
Для исправления ошибки нам необходимо явно указать платформе, что поле Ссылка должно рассматриваться как конкретный тип справочника. Перепишем условие связи следующим образом:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ...) КАК Цены
ПО (ВЫРАЗИТЬ(СправочникНоменклатура.Ссылка КАК Справочник.Номенклатура) = Цены.Номенклатура)
Проанализируем, что происходит в этот момент: оператор ВЫРАЗИТЬ заставляет SQL-сервер использовать конкретные типизированные таблицы для сопоставления данных. Это снимает неопределенность, возникшую из-за работы механизма расширений, и позволяет запросу выполниться корректно.
Важно знать, что данное поведение официально признано багом платформы 1С. Если у вас есть возможность управлять системным окружением, лучшим долгосрочным решением будет обновление версии платформы «1С:Предприятие».
Посмотрим на список релизов, в которых данная проблема была устранена:
Если ваша информационная база работает на версии ниже указанных, применение ВЫРАЗИТЬ является обязательным для стабильной работы динамического списка в расширении.
Динамический список базируется на системе компоновки данных (СКД). Иногда ошибка проявляется из-за некорректной работы механизма «Автозаполнение». Проанализируем альтернативный вариант исправления:
Справочник.Номенклатура). Это критически важно для корректного построения индексов и типизации.Рассмотрим важный нюанс: использование оператора ВЫРАЗИТЬ в условиях связи (секция ПО) может повлиять на производительность. В некоторых СУБД это может привести к невозможности использования индексов (так называемая проблема SARGability), что замедлит работу списка на больших объемах данных (например, если в справочнике номенклатуры сотни тысяч элементов).
Рекомендация: после того как вы обновите платформу до актуального исправленного релиза, мы рекомендуем вернуться в текст запроса и убрать конструкцию ВЫРАЗИТЬ, вернув стандартное сравнение ссылок ПО СправочникНоменклатура.Ссылка = Цены.Номенклатура. Это позволит оптимизатору запросов СУБД работать максимально эффективно.
Посмотрим, как должен выглядеть полный текст запроса для динамического списка (фрагмент) с учетом всех исправлений:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Наименование КАК Наименование,
ЕСТЬNULL(ХозрасчетныйОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
{ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаОстаткиЦены,
{(Номенклатура).* КАК Ссылка, (ТипЦен) КАК ТипЦен}) КАК ЦеныНоменклатурыСрезПоследних
ПО (ВЫРАЗИТЬ(СправочникНоменклатура.Ссылка КАК Справочник.Номенклатура) = ЦеныНоменклатурыСрезПоследних.Номенклатура)}
{ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Остатки(&ДатаОстаткиЦены, Счет В (&СчетаЗапасов), , ) КАК ХозрасчетныйОстатки
ПО (ВЫРАЗИТЬ(СправочникНоменклатура.Ссылка КАК Справочник.Номенклатура) = ХозрасчетныйОстатки.Субконто1)}
ГДЕ
НЕ СправочникНоменклатура.ЭтоГруппа
Используя данный подход, мы гарантируем стабильную работу расширения независимо от «капризов» механизма типизации в текущем релизе платформы.