Определяем, на что указывает ссылка в 1С: от формы пользователя до запроса

· 9 мин

Содержание

В коде тип ссылки проверяют так: ТипЗнч(Значение) = Тип("СправочникСсылка.Контрагенты"). В запросе это делают через ССЫЛКА или ТИПЗНАЧЕНИЯ(). Пользователю без конфигуратора хватит навигационной ссылки объекта: в ней прямо написано, справочник это или документ и как он называется, например e1cib/data/Документ.РеализацияТоваровУслуг?ref=....

Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: одинаково работает в БП 3.0, ЗУП 3.1, УТ 11 и самописных базах. Отличаются только имена объектов метаданных.

Ссылка в 1С и какие типы ссылок бывают

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

Ссылочные типы есть у каждого объекта метаданных, который хранит записи с идентификатором:

Объект метаданныхИмя ссылочного типаПример
СправочникСправочникСсылка.<Имя>СправочникСсылка.Номенклатура
ДокументДокументСсылка.<Имя>ДокументСсылка.ПоступлениеТоваровУслуг
ПеречислениеПеречислениеСсылка.<Имя>ПеречислениеСсылка.СтавкиНДС
План видов характеристикПланВидовХарактеристикСсылка.<Имя>—
План счетовПланСчетовСсылка.<Имя>ПланСчетовСсылка.Хозрасчетный
План видов расчётаПланВидовРасчетаСсылка.<Имя>—
План обменаПланОбменаСсылка.<Имя>—
Бизнес-процесс, задачаБизнесПроцессСсылка.<Имя>, ЗадачаСсылка.<Имя>—

Регистры сведений, накопления и бухгалтерии ссылок не имеют. Их записи идентифицируются набором измерений или регистратором.

Проверять тип приходится, когда поле может хранить значения разных типов:

  • 🔀 составной тип реквизита — например, «Контрагент или физлицо»;
  • 📑 регистратор в регистрах — документ любого вида, который делает движения;
  • 🧾 субконто на счетах — на 60 это контрагент и договор, на 41 — номенклатура и склад;
  • 🧩 характеристики из планов видов характеристик — тип значения зависит от вида;
  • 📦 параметры процедур — когда общая функция получает «что-то ссылочное».

Как узнать тип ссылки без конфигуратора и кода

Обычному пользователю тип объекта нужен реже, но бывает: разработчик просит прислать «ссылку на документ», техподдержка спрашивает, откуда взялось значение в отчёте. Есть три способа.

Навигационная ссылка объекта

  1. Откройте карточку справочника или документа.
  2. Вызовите команду получения ссылки: в интерфейсе «Такси» это Shift+F11 или значок ссылки в заголовке формы.
  3. Скопируйте строку из окна.

Строка выглядит так: e1cib/data/Справочник.Контрагенты?ref=8f3a00155d0a6b1211ee.... Часть между data/ и ?ref= — это и есть тип объекта: вид метаданных и его имя. По такой ссылке коллега откроет тот же объект через Перейти по ссылке.

Окно выбора типа в составном поле

Если поле составного типа ещё пустое и вы нажимаете кнопку выбора, платформа сначала показывает окно «Выбор типа данных». В нём перечислены все типы, которые разрешил разработчик для этого реквизита. Так видно, какие значения поле вообще принимает.

Обработка «Поиск ссылок на объект»

Обработка показывает, в каких документах и справочниках используется выбранный объект, и указывает их вид. Это стандартная обработка платформы.

  1. Включите команду: Главное меню → Сервис → Параметры, флажок «Отображать команду “Все функции”».
  2. Откройте Главное меню → Все функции → Стандартные → Поиск ссылок на объект.
  3. Выберите объект и запустите поиск.

Если в отчёте вы видите строку <Объект не найден> с длинным кодом, это битая ссылка: тип записан, а записи в таблице уже нет. Обычно так бывает после непосредственного удаления или неудачного обмена.

Тип ссылки в конфигураторе и отладчике

Разработчику тип поля сначала нужно посмотреть в метаданных, а потом — в живых данных при отладке.

Свойство «Тип» у реквизита

  1. В дереве метаданных откройте объект и нужный реквизит.
  2. В палитре свойств найдите свойство «Тип».
  3. Если отмечен флажок «Составной тип данных», в списке будут все разрешённые типы.

Тип может быть задан не перечнем, а через Общие → Определяемые типы. Тогда реквизит ссылается на определяемый тип, и состав смотрят уже в нём. В типовых конфигурациях на БСП так устроены многие поля «Владелец», «Объект», «Организация».

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

Чтобы найти, где ещё используется справочник или документ, щёлкните по нему в дереве правой кнопкой и выберите Поиск ссылок на объект. Конфигуратор покажет все реквизиты, измерения и параметры, где этот тип разрешён.

Отладчик: «Вычислить выражение» и табло

  1. Поставьте точку останова (F9) на строке, где переменная уже заполнена.
  2. Запустите отладку и дождитесь остановки.
  3. Выделите переменную и нажмите Shift+F9 или добавьте её в табло.

В колонке «Тип» отладчик выводит тип значения. Там же можно вычислить выражение ТипЗнч(Регистратор) или Метаданные.НайтиПоТипу(ТипЗнч(Регистратор)).ПолноеИмя(), чтобы увидеть имя объекта метаданных строкой.

Программные методы определения типа ссылки

Основных приёмов пять. Какой брать, зависит от вопроса: «это конкретный справочник?», «это вообще справочник?» или «что это за объект?».

Сравнение с конкретным типом: ТипЗнч и Тип

Самый частый случай — разветвить логику под пару известных типов.

Если ТипЗнч(Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
    ИНН = Контрагент.ИНН;
ИначеЕсли ТипЗнч(Контрагент) = Тип("СправочникСсылка.ФизическиеЛица") Тогда
    ИНН = Контрагент.ИНН;
ИначеЕсли ТипЗнч(Контрагент) = Тип("Неопределено") Тогда
    ИНН = "";
КонецЕсли;

ТипЗнч() возвращает значение типа Тип. Сравнивать его надо тоже с Тип, а не со строкой. Имя в Тип("...") пишется через СправочникСсылка, ДокументСсылка и так далее.

Проверка на несколько типов: ОписаниеТипов

Когда разрешённых типов много, удобнее собрать их в описание типов и проверить одним вызовом:

Допустимые = Новый ОписаниеТипов("СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица");
Если Допустимые.СодержитТип(ТипЗнч(Значение)) Тогда
    // значение подходит
КонецЕсли;

Класс объекта: ТипВсеСсылки

Если важно не имя, а вид — справочник это или документ, — используйте менеджеры коллекций:

ТипЗначения = ТипЗнч(Значение);
Если Справочники.ТипВсеСсылки().СодержитТип(ТипЗначения) Тогда
    Вид = "Справочник";
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипЗначения) Тогда
    Вид = "Документ";
ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипЗначения) Тогда
    Вид = "Перечисление";
Иначе
    Вид = "Не ссылка или другой вид";
КонецЕсли;

ТипВсеСсылки() возвращает ОписаниеТипов со всеми ссылками этого вида в конфигурации. Метод есть и у ПланыВидовХарактеристик, ПланыСчетов, ПланыОбмена, БизнесПроцессы, Задачи.

Имя объекта метаданных: Метаданные.НайтиПоТипу

Универсальный способ узнать, на что указывает ссылка, не зная заранее вариантов:

Функция ПолноеИмяПоЗначению(Значение) Экспорт
    ОбъектМД = Метаданные.НайтиПоТипу(ТипЗнч(Значение));
    Если ОбъектМД = Неопределено Тогда
        Возврат "";
    КонецЕсли;
    Возврат ОбъектМД.ПолноеИмя();
КонецФункции

Для ссылки на документ поступления функция вернёт Документ.ПоступлениеТоваровУслуг. Для строки, числа или Неопределено — пустую строку. Дальше вид можно проверить так: Метаданные.Справочники.Содержит(ОбъектМД).

Готовые функции БСП

В типовых конфигурациях на Библиотеке стандартных подсистем писать свои проверки обычно не нужно. В общем модуле ОбщегоНазначения есть:

  • ✅ ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Значение)) — Истина, если тип ссылочный;
  • 🔎 ОбщегоНазначения.СсылкаСуществует(Ссылка) — есть ли запись в базе (ловит битые ссылки);
  • 🏷️ ОбщегоНазначения.ИмяТаблицыПоСсылке(Ссылка) — полное имя таблицы, например Справочник.Номенклатура.

Проверка типа в запросе

В языке запросов есть два оператора. ССЫЛКА отвечает на вопрос «указывает ли поле на эту таблицу», ТИПЗНАЧЕНИЯ() возвращает тип для сравнения или вывода.

ВЫБРАТЬ
    Хозрасчетный.Регистратор КАК Регистратор,
    ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) КАК ТипРегистратора
ИЗ
    РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
    Хозрасчетный.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Эквивалентное условие через тип: ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) = ТИП(Документ.РеализацияТоваровУслуг). Внутри запроса имя типа пишут без слова «Ссылка».

СпособГде работаетКогда брать
ТипЗнч() = Тип()клиент и серверодин-два известных типа
ОписаниеТипов.СодержитТип()клиент и серверсписок допустимых типов
ТипВсеСсылки()сервернужен вид: справочник, документ
Метаданные.НайтиПоТипу()серверимя объекта заранее неизвестно
ССЫЛКА, ТИПЗНАЧЕНИЯ()запросотбор и группировка по типу
Что именно вам нужно узнать о ссылке?

Ошибки при проверке типа ссылки и как их обойти

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

  • ❌ Сравнение со строкой. ТипЗнч(Х) = "СправочникСсылка.Контрагенты" синтаксически допустимо, но всегда даёт Ложь: значение типа Тип строке не равно.
  • ❌ Пропущено «Ссылка» в имени. Тип("Справочник.Контрагенты") вызывает ошибку Тип не определен (Справочник.Контрагенты). Та же ошибка будет при опечатке в имени объекта.
  • ❌ Пустое значение составного поля. Пустой реквизит составного типа содержит Неопределено, а не пустую ссылку. Вызов Значение.Метаданные() на нём падает с ошибкой «Значение не является значением объектного типа». Сначала проверьте ЗначениеЗаполнено(Значение).
  • ❌ Реквизит через точку без проверки типа. Если в поле оказался объект другого типа, обращение Контрагент.ИНН даст «Поле объекта не обнаружено (ИНН)». Перед точкой убедитесь в типе.
  • ❌ Чтение реквизитов на клиенте. Сравнить тип ссылки на клиенте можно, а получить реквизит через точку — нет. Данные читайте в серверной процедуре.
  • ❌ Точка через составное поле в запросе. Хозрасчетный.Субконто1.ИНН заставляет платформу соединить таблицу со всеми справочниками, которые могут попасть в субконто. Запрос заметно тяжелеет. Решение — ВЫРАЗИТЬ, о нём ниже.

Битые ссылки ищите только чтением: запросом или функцией СсылкаСуществует. Не запускайте «Тестирование и исправление» с вариантом очистки ссылок на рабочей базе без резервной копии — это удалит значения из реквизитов, и восстановить их будет нечем.

Составные поля, субконто и характеристики: проверка «плавающих» ссылок

Динамическими обычно называют поля, тип которых становится известен только по данным: составные реквизиты, Регистратор, субконто, значения характеристик, параметры с типом ЛюбаяСсылка.

ВЫРАЗИТЬ: приведение к одному типу в запросе

ВЫРАЗИТЬ говорит платформе: «рассматривай поле как ссылку на эту таблицу». Если фактически там другой тип, результат будет NULL.

ВЫБРАТЬ
    ВЫРАЗИТЬ(Остатки.Субконто1 КАК Справочник.Контрагенты) КАК Контрагент,
    ВЫРАЗИТЬ(Остатки.Субконто1 КАК Справочник.Контрагенты).ИНН КАК ИНН,
    Остатки.СуммаОстаток КАК Сумма
ИЗ
    РегистрБухгалтерии.Хозрасчетный.Остатки(&Дата, Счет = &Счет, , ) КАК Остатки
ГДЕ
    Остатки.Субконто1 ССЫЛКА Справочник.Контрагенты

Условие ССЫЛКА в ГДЕ отсекает строки с другими типами субконто, а ВЫРАЗИТЬ даёт короткое соединение только с одной таблицей.

Характеристики

Тип значения характеристики определяется видом характеристики. В коде это читают из самого вида:

ТипыВида = ВидХарактеристики.ТипЗначения; // ОписаниеТипов
Если ТипыВида.СодержитТип(Тип("СправочникСсылка.Номенклатура")) Тогда
    // значение этого вида может быть номенклатурой
КонецЕсли;

Само сохранённое значение проверяют обычным ТипЗнч(): вид говорит, что допустимо, а данные — что записано фактически.

Навигационные ссылки в коде

Функция ПолучитьНавигационнуюСсылку(Ссылка) возвращает ту же строку e1cib/data/..., что видит пользователь. Её удобно писать в журнал регистрации или письмо: по строке сразу видно тип, и объект открывается одним кликом.

Практические сценарии: тип ссылки в типовых задачах

Обработчик подписки на событие

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

Процедура ПередЗаписьюДокумента(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
    ТипСсылки = ТипЗнч(Источник.Ссылка);
    Если ТипСсылки = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
        // проверки для реализации
    ИначеЕсли ТипСсылки = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") Тогда
        // проверки для поступления
    КонецЕсли;
КонецПроцедуры

У нового, ещё не записанного документа Источник.Ссылка пустая, но её тип уже правильный. Поэтому сравнение по типу ссылки работает и при первой записи.

Отчёт по регистраторам

Чтобы понять, какие виды документов двигают регистр и сколько строк дал каждый, сгруппируйте по типу:

ВЫБРАТЬ
    ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) КАК ВидДокумента,
    КОЛИЧЕСТВО(*) КАК Строк
ИЗ
    РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
    Хозрасчетный.Период МЕЖДУ &Начало И &Конец
СГРУППИРОВАТЬ ПО
    ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор)

Универсальная обработка по любому объекту

Если обработка принимает «любой объект» и должна открыть его форму или выгрузить таблицу, сначала узнайте имя таблицы через Метаданные.НайтиПоТипу или ИмяТаблицыПоСсылке. Затем подставьте его в текст запроса: "ВЫБРАТЬ * ИЗ " + ИмяТаблицы + " ГДЕ Ссылка = &Ссылка". Имя берите только из метаданных, не из пользовательского ввода.

Частые вопросы

Чем ТИПЗНАЧЕНИЯ отличается от ССЫЛКА в запросе?
ССЫЛКА — логическое условие «поле указывает на эту таблицу». ТИПЗНАЧЕНИЯ возвращает сам тип: его можно вывести в колонку, сгруппировать или сравнить с ТИП(…).
Как отличить пустую ссылку от Неопределено?
У пустой ссылки тип конкретный, например СправочникСсылка.Контрагенты, и метод Пустая() возвращает Истина. У Неопределено тип Неопределено. ЗначениеЗаполнено() вернёт Ложь в обоих случаях.
Можно ли получить тип в виде строки?
Да. Метаданные.НайтиПоТипу(ТипЗнч(Значение)).ПолноеИмя() даёт имя вида «Справочник.Номенклатура». Для обмена данными есть XMLТипЗнч(Значение).ИмяТипа — оно вернёт англоязычное имя вроде CatalogRef.Номенклатура.
Почему проверка типа работает в отладчике, а в рабочем коде нет?
Чаще всего код выполняется на клиенте, и на нём пытаются прочитать реквизит через точку. Либо значение пришло как Неопределено из пустого составного поля. Проверьте контекст процедуры и заполненность.