Почему в 1С возникает ошибка «Эти данные невозможно выбрать, так как они были ранее удалены» при автоподборе нового контрагента и как ее исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

В этой статье мы подробно разберем, почему возникает это поведение, рассмотрим внутренние механизмы платформы 1С:Предприятие 8.3, отвечающие за кэширование данных на клиенте, и внедрим пошаговые решения для устранения этой проблемы.

Выясняем причину: почему платформа «считает» новый объект удаленным?

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

Когда внешняя обработка или код формы генерирует новый GUID и на его основе получает ссылку с помощью метода ПолучитьСсылку(), эта ссылка передается на клиентскую сторону (в тонкий или веб-клиент) еще до того, как транзакция записи объекта в базу данных будет полностью завершена и зафиксирована.

В этот критический момент происходят следующие события:

  1. Запрос представления ссылки на клиенте: Тонкий клиент получает ссылку на объект, которого фактически еще нет в таблицах СУБД. Платформа пытается получить текстовое представление для этой ссылки, чтобы отобразить его пользователю.
  2. Кэширование статуса «несуществования»: Так как объект в БД еще отсутствует, платформа определяет ссылку как битую (несуществующую). На клиенте срабатывает встроенный оптимизационный механизм: статус этой ссылки кэшируется как «удален/не существует», а вместо наименования записывается шаблон <Объект не найден>. Это необходимо для того, чтобы клиент постоянно не слал тяжелые запросы к серверу для отображения заведомо битых ссылок.
  3. Конфликт при автоподборе: После успешной записи контрагента на сервере он физически появляется в базе данных. Когда пользователь начинает вводить первые символы в поле ввода, стандартный механизм автоподбора отрабатывает на сервере, находит этого контрагента по наименованию и возвращает массив ссылок в ДанныеВыбора. Однако, когда платформа на клиенте пытается сопоставить полученную ссылку с локальным кэшем представлений, она видит сохраненный ранее статус «удален». Это приводит к блокировке выбора элемента и генерации системного сообщения об ошибке.

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

---

Решение 1: Принудительный сброс кэша с помощью метода ОповеститьОбИзменении()

Самым простым, надежным и штатным способом решения данной проблемы является принудительная очистка клиентского кэша представлений. Платформа 1С предоставляет для этого специальный метод ОповеститьОбИзменении(). Этот метод сообщает открытым формам и локальным кэшам клиента о том, что данные конкретного объекта или типа данных изменились, требуя их немедленного обновления.

Рассмотрим, как правильно применить этот метод в коде. Сразу после вызова серверной процедуры создания и записи контрагента, на стороне клиента мы должны выполнить оповещение:


// На клиенте после программного создания контрагента
&НаКлиенте
Процедура СоздатьНовогоКонтрагентаИВыбрать()
    
    // Вызываем серверный метод создания объекта, который возвращает нам ссылку
    НовыйКонтрагентСсылка = СоздатьКонтрагентаНаСервере();
    
    Если ЗначениеЗаполнено(НовыйContрагентСсылка) Тогда
        // Сбрасываем кэш представлений для конкретной созданной ссылки
        ОповеститьОбИзменении(НовыйКонтрагентСсылка);
        
        // Теперь ссылка гарантированно обновит свой статус на клиенте
        // и будет доступна для автоподбора без ошибок
    КонецЕсли;
    
КонецПроцедуры

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

ОповеститьОбИзменении(Тип("СправочникСсылка.Контрагенты")); ---

Решение 2: Оптимизация серверного кода (исключение передачи ссылки до записи)

Для предотвращения кэширования «несуществования» ссылки лучшим архитектурным решением будет изоляция процесса генерации ссылки и записи объекта. Нельзя допускать передачи сгенерированной ссылки (GUID) на клиент до того, как объект будет физически сохранен в базе данных.

Рассмотрим правильный паттерн программного создания нового элемента справочника на сервере:


&НаСервереБезКонтекста
Функция СоздатьКонтрагентаНаСервере(НаименованиеКонтрагента)
    
    // Создаем новый идентификатор
    НовыйУИД = Новый УникальныйИдентификатор();
    
    // Создаем ссылку на основе этого идентификатора
    НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(НовыйУИД);
    
    // Создаем сам объект справочника
    НовыйОбъект = Справочники.Контрагенты.СоздатьЭлемент();
    
    // Важно: привязываем созданную ссылку к объекту ДО первой записи
    НовыйОбъект.УстановитьСсылкуНового(НоваяСсылка);
    
    // Заполняем реквизиты
    НовыйОбъект.Наименование = НаименованиеКонтрагента;
    
    Попытка
        // Запись должна происходить в этой же серверной транзакции
        НовыйОбъект.Записать();
        Возврат НоваяСсылка;
    Исключение
        ЗаписьЖурналаРегистрации("СозданиеКонтрагента", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        ВызватьИсключение "Не удалось записать нового контрагента!";
    КонецПопытки;
    
КонецФункции

Используя данный подход, клиент получает ссылку на объект только тогда, когда этот объект уже гарантированно записан в базу данных. Локальный кэш клиента никогда не зафиксирует статус «Объект не найден» для этой ссылки.

---

Решение 3: Отключение истории выбора при вводе на форме

Иногда ошибка усугубляется тем, что некорректная пустая ссылка оседает в так называемой «Истории выбора» конкретного элемента формы у пользователя. Если вам необходимо полностью исключить влияние истории выбора на процесс автоподбора, выполните следующие шаги в конфигураторе:

  1. Откройте форму документа или обработки, где расположено поле ввода (например, поле Плательщик).
  2. Выделите это поле ввода и откройте палитру Свойств.
  3. Найдите группу свойств «Параметры выбора» или «Использование».
  4. Найдите свойство «История выбора при вводе» (Choice history on input).
  5. Установите значение этого свойства в положение «Не использовать».

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

---

Решение 4: Программная обработка получения данных выбора

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

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


// В модуле менеджера справочника Контрагенты
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
    
    // Если нам нужно переопределить стандартный поиск
    СтандартнаяОбработка = Ложь;
    
    СписокВыбора = Новый СписокЗначений;
    
    // Выполняем прямой запрос к актуальным таблицам БД
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ
        |	Контрагенты.Ссылка КАК Ссылка,
        |	Контрагенты.Наименование КАК Наименование
        |ИЗ
        |	Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |	Контрагенты.Наименование ПОДОБНО &СтрокаПоиска + ""%""";
        
    Запрос.УстановитьПараметр("СтрокаПоиска", Параметры.СтрокаПоиска);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        СписокВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
    КонецЦикла;
    
    ДанныеВыбора = СписокВыбора;
    
КонецПроцедуры

Таким образом, комбинируя архитектурно правильное создание объектов на сервере и своевременный сброс клиентского кэша с помощью ОповеститьОбИзменении(), вы навсегда избавите ваших пользователей от досадных ошибок несоответствия кэша представлений в управляемом приложении 1С.

← На главную