Почему запрос 1С возвращает пустой результат после смены типа реквизита со Строки на Ссылку?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

В процессе доработки конфигураций 1С часто возникает задача изменить тип данных у реквизита. Классический пример — замена строкового поля, в котором хранилось наименование, на ссылку на соответствующий элемент справочника. Это правильный шаг с точки зрения архитектуры, так как обеспечивает целостность данных. Однако после такого изменения часто перестают работать запросы, которые раньше исправно фильтровали данные по этому полю. Рассмотрим типичную ситуацию: запрос по оборудованию перестал находить записи по цеху после того, как реквизит "Цех" был изменен со типа Строка на СправочникСсылка.

Проанализируем, почему это происходит и как исправить ситуацию, разобрав все по шагам.

Анализируем проблему: что пошло не так?

Представим исходную ситуацию. У нас есть справочник "ЗаводскоеОборудование" и запрос, который отбирает оборудование по указанному цеху. Изначально реквизит "Цех" имел тип Строка, и код выглядел примерно так:


// Старый, работающий вариант (реквизит "Цех" - Строка)
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ЗаводскоеОборудование.Ссылка
    |ИЗ
    |    Справочник.ЗаводскоеОборудование КАК ЗаводскоеОборудование
    |ГДЕ
    |    ЗаводскоеОборудование.Цех = &Цех";

Запрос.УстановитьПараметр("Цех", "Сборочный цех №1"); // Передаем строку
Результат = Запрос.Выполнить();

После рефакторинга мы создали справочник "Цеха", а в справочнике "ЗаводскоеОборудование" изменили реквизит. Теперь он называется ЦехСсылка и имеет тип СправочникСсылка.Цеха. Код запроса был изменен соответствующим образом:


// Новый, неработающий вариант (реквизит "ЦехСсылка" - Ссылка)
Запрос3 = Новый Запрос(
    "ВЫБРАТЬ
    |    ЗаводскоеОборудование.Ссылка,
    |    ЗаводскоеОборудование.ЦехСсылка
    |ИЗ
    |    Справочник.ЗаводскоеОборудование КАК ЗаводскоеОборудование
    |ГДЕ
    |    ЗаводскоеОборудование.ЦехСсылка = &ЦехСсылка"
);

// Переменная ЦехСсылка содержит ссылку на элемент справочника "Цеха"
Запрос3.УстановитьПараметр("ЦехСсылка", ЦехСсылка); 
Результат3 = Запрос3.Выполнить(); // Запрос выполняется без ошибок
Выборка = Результат3.Выбрать(); // А выборка оказывается пустой

Главный симптом проблемы — запрос выполняется без ошибок, но возвращает пустой результат. При отладке видно, что в параметр &ЦехСсылка передается корректная ссылка на цех, но условие ГДЕ не находит ни одной подходящей записи. Это ключевой момент: пустой результат означает, что в базе данных нет записей, удовлетворяющих условию. Выясним, почему так происходит.

Шаг 1: Проверяем данные после смены типа

Самая частая ошибка заключается в предположении, что 1С автоматически преобразует данные после смены типа реквизита в конфигураторе. Это не так.

Когда вы меняете тип реквизита со Строка на СправочникСсылка и обновляете базу данных, платформа не знает, как сопоставить старые строковые значения ("Сборочный цех №1") с новыми ссылками на элементы справочника "Цеха". В результате все значения в этом поле просто "обнуляются", то есть становятся пустыми ссылками (NULL в терминах СУБД).

Чтобы убедиться в этом, воспользуемся мощнейшим инструментом разработчика — Консолью запросов.

  1. Откройте консоль запросов в режиме "Предприятие".
  2. Выполните запрос, который покажет все уникальные значения и их типы в измененном поле. Условие ГДЕ нужно убрать, чтобы увидеть всю картину.

ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗаводскоеОборудование.ЦехСсылка,
    ТИПЗНАЧЕНИЯ(ЗаводскоеОборудование.ЦехСсылка) КАК ТипРеквизита
ИЗ
    Справочник.ЗаводскоеОборудование КАК ЗаводскоеОборудование

Скорее всего, результат этого запроса покажет одну строку, где в поле ЦехСсылка будет значение <Объект не найден> или NULL, а в поле ТипРеквизита — тип вашего нового справочника. Это прямое доказательство того, что данные не были конвертированы и все ссылки в базе пустые. Естественно, сравнение пустой ссылки со ссылкой на конкретный цех в условии ГДЕ всегда даст ложный результат.

Шаг 2: Выявляем фундаментальную ошибку в типе данных

В ходе обсуждения на форуме вскрылась еще одна, более глубокая и коварная ошибка. Автор указал, что изменил тип реквизита ЦехСсылка на... СправочникСсылка.ЗаводскоеОборудование.

Это логическая ошибка в проектировании данных.

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

Каковы последствия такой ошибки для запроса? Они фатальны. Давайте разберем, что происходит на уровне типов:

Система типов в 1С строгая. Запрос ГДЕ ЗаводскоеОборудование.ЦехСсылка = &ЦехСсылка пытается сравнить значения двух разных типов. Такое сравнение всегда вернет ЛОЖЬ, даже если данные были бы как-то заполнены. Платформа просто не может приравнять ссылку на цех к ссылке на оборудование.

Разрабатываем план исправления

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

1. Корректировка конфигурации

Первым делом необходимо исправить ошибку в структуре данных.

  1. Откройте конфигуратор.
  2. Найдите справочник ЗаводскоеОборудование и откройте его.
  3. Перейдите на вкладку "Данные" и найдите реквизит ЦехСсылка.
  4. Откройте его свойства и измените тип данных с некорректного СправочникСсылка.ЗаводскоеОборудование на правильный, например, СправочникСсылка.Цеха.
  5. Сохраните конфигурацию и обновите базу данных (F7).

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

2. Конвертация данных с помощью обработки

Теперь необходимо заполнить реквизит ЦехСсылка правильными значениями на основе старых строковых данных. Для этого нужно написать специальную обработку. Логика ее работы будет следующей: пройти по всем элементам справочника "ЗаводскоеОборудование", для каждого найти соответствующий цех в справочнике "Цеха" и записать ссылку.

Для поиска соответствия нам понадобится старое строковое значение. Если вы его нигде не сохранили перед сменой типа, возможно, придется восстанавливать его из бэкапа или из других полей (например, из наименования оборудования). В примере ниже предположим, что вы предусмотрительно сохранили старые значения во временном реквизите СтарыйЦехСтрокой.

Пример кода для обработки конвертации:


// Этот код должен выполняться в привилегированном режиме
// в специальной обработке для конвертации данных.

Процедура КонвертироватьДанные()

    // Выбираем все элементы справочника для обработки
    ВыборкаОборудования = Справочники.ЗаводскоеОборудование.Выбрать();

    Пока ВыборкаОборудования.Следующий() Цикл
        // Получаем объект, чтобы иметь возможность его изменить и записать
        ОбъектОборудования = ВыборкаОборудования.ПолучитьОбъект();
        
        // Если ссылка уже заполнена (например, при повторном запуске), пропускаем
        Если ЗначениеЗаполнено(ОбъектОборудования.ЦехСсылка) Тогда
            Продолжить;
        КонецЕсли;

        // Получаем старое строковое наименование цеха из временного поля
        НаименованиеЦеха = ОбъектОборудования.СтарыйЦехСтрокой; 
        
        Если НЕ ЗначениеЗаполнено(НаименованиеЦеха) Тогда
            Сообщить("Для оборудования '" + ОбъектОборудования.Наименование + "' не найдено старое значение цеха.");
            Продолжить;
        КонецЕсли;
        
        // Ищем соответствующий цех в справочнике "Цеха" по наименованию
        // Для надежности лучше использовать поиск по коду, если он есть
        НайденныйЦех = Справочники.Цеха.НайтиПоНаименованию(НаименованиеЦеха);
        
        Если НайденныйЦех.Пустая() Тогда
            Сообщить("Не удалось найти цех с наименованием '" + НаименованиеЦеха + "'. Проверьте справочник 'Цеха'.");
        Иначе
            // Заполняем новый реквизит и записываем объект
            ОбъектОборудования.ЦехСсылка = НайденныйЦех;
            Попытка
                // Рекомендуется отключить проверки и контроль записи для ускорения
                ОбъектОборудования.Записать(РежимЗаписиДокумента.Запись);
            Исключение
                Сообщить("Ошибка записи для оборудования: " + ОбъектОборудования.Ссылка + ". " + ОписаниеОшибки());
            КонецПопытки;
        КонецЕсли;
        
    КонецЦикла;

    Сообщить("Конвертация данных завершена.");

КонецПроцедуры

После выполнения этой обработки все элементы справочника "ЗаводскоеОборудование" будут иметь корректно заполненные ссылки на цеха, и ваш изначальный запрос наконец-то начнет работать правильно.

Итоги и рекомендации по отладке

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

  1. Данные не были конвертированы. Простое изменение типа в конфигураторе обнуляет значения.
  2. Назначен неверный ссылочный тип. Запрос не может сравнивать значения разных типов.

Чтобы избежать подобных проблем в будущем и эффективно их отлаживать, придерживайтесь следующих правил:

← На главную