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

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

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

Проанализируем ситуацию: чтобы значение успешно записалось в реквизит ссылочного типа, переменная должна содержать не строковое представление, а конкретную ссылку на объект базы данных (тип СправочникСсылка, ДокументСсылка и т. д.). Разберем по шагам основные способы получения ссылки из строки в зависимости от формата входных данных.

Способ 1. Поиск элемента по наименованию

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

Рассмотрим пример кода:


ИмяРеквизита = "Контрагент";
ЗначениеРеквизита = "ООО Ромашка";

// Выполняем точный поиск по наименованию
СсылкаКонтрагент = Справочники.Контрагенты.НайтиПоНаименованию(СокрЛП(ЗначениеРеквизита), Истина);

Если Не СсылкаКонтрагент.Пустая() Тогда
    МойДок[ИмяРеквизита] = СсылкаКонтрагент;
Иначе
    // Обработка ситуации, когда элемент не найден в базе данных
    ВызватьИсключение "Контрагент с наименованием """ + ЗначениеРеквизита + """ не найден!";
КонецЕсли;

Обратим внимание на второй параметр метода НайтиПоНаименованию(): установка значения Истина включает режим точного соответствия. Перед поиском рекомендуется использовать функцию СокрЛП(), чтобы исключить случайные пробелы по краям строки.

Способ 2. Поиск по коду или дополнительному реквизиту (ИНН, артикул)

Поиск по наименованию не всегда надежен, так как в базе могут существовать дубли с одинаковыми названиями. Если в строке передан код элемента или уникальный реквизит (например, ИНН для контрагента или артикул для номенклатуры), лучше использовать специализированные методы поиска.

Посмотрим на примеры:


// Поиск по коду справочника
СсылкаПоКоду = Справочники.Контрагенты.НайтиПоКоду(СокрЛП(ЗначениеРеквизита));

// Поиск по произвольному реквизиту (например, ИНН)
СсылкаПоИНН = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", СокрЛП(ЗначениеРеквизита));

Если Не СсылкаПоИНН.Пустая() Тогда
    МойДок.Контрагент = СсылкаПоИНН;
КонецЕсли;

Способ 3. Получение ссылки по уникальному идентификатору (GUID)

Если строка представляет собой строковое представление GUID (например, "e1cbb3d8-1234-5678-9abc-def012345678"), ссылку можно получить напрямую без выполнения поискового запроса к таблице.

Разберем два варианта реализации:

  1. Через объект УникальныйИдентификатор:
    
    СтрокаGUID = "e1cbb3d8-1234-5678-9abc-def012345678";
    УИД = Новый УникальныйИдентификатор(СтрокаGUID);
    Ссылка = Справочники.Контрагенты.ПолучитьСсылку(УИД);
    
  2. Через функцию сериализации XMLЗначение(): Ссылка = XMLЗначение(Тип("СправочникСсылка.Контрагенты"), СтрокаGUID);

Важное ограничение: Метод ПолучитьСсылку() формирует ссылку в памяти. Если объекта с таким идентификатором в информационной базе нет, будет получена «битая» ссылка. Чтобы убедиться в существовании объекта, необходимо проверить его запросом или обращением к реквизиту через точку.

Способ 4. Динамическое определение типа реквизита через метаданные

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

Рассмотрим универсальный алгоритм:


ИмяРеквизита = "Контрагент";
ЗначениеРеквизита = "ООО Ромашка";

// 1. Получаем описание типов реквизита из метаданных объекта
ОписаниеТиповРеквизита = МойДок.Метаданные().Реквизиты[ИмяРеквизита].Тип;
МассивТипов = ОписаниеТиповРеквизита.Типы();

Если МассивТипов.Количество() > 0 Тогда
    ТипРеквизита = МассивТипов[0];
    ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипРеквизита);
    
    // Проверяем, что реквизит относится к справочникам
    Если Метаданные.Справочники.Содержит(ОбъектМетаданных) Тогда
        МенеджерСправочника = Справочники[ОбъектМетаданных.Имя];
        НайденнаяСсылка = МенеджерСправочника.НайтиПоНаименованию(СокрЛП(ЗначениеРеквизита), Истина);
        
        Если Не НайденнаяСсылка.Пустая() Тогда
            МойДок[ИмяРеквизита] = НайденнаяСсылка;
        КонецЕсли;
    КонецЕсли;
КонецЕсли;

Способ 5. Поиск с помощью запроса (при массовой загрузке)

Если требуется обработать не один документ, а массив строк (например, при импорте прайс-листа или загрузке банковской выписки), вызывать методы НайтиПоНаименованию() или НайтиПоКоду() в цикле крайне не рекомендуется. Каждый такой вызов формирует отдельный запрос к СУБД, что сильно замедляет работу.

В таких случаях эффективнее собрать все строковые значения в таблицу значений и выполнить пакетный поиск одним запросом к базе данных.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ТаблицаЗначений.Наименование КАК Наименование
    |ПОМЕСТИТЬ ВТ_ДанныеДляПоиска
    |ИЗ
    |   &ТаблицаДанных КАК ТаблицаЗначений
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |   ВТ.Наименование КАК Наименование,
    |   Контрагенты.Ссылка КАК КонтрагентСсылка
    |ИЗ
    |   ВТ_ДанныеДляПоиска КАК ВТ
    |   ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
    |       ПО ВТ.Наименование = Контрагенты.Наименование
    |           И НЕ Контрагенты.ПометкаУдаления";

Запрос.УстановитьПараметр("ТаблицаДанных", ИсходнаяТаблица);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

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

← На главную