Ссылка на объект в 1С 8.3: от получения в коде до поиска «Объект не найден»
Содержание
Работать со ссылками в 1С — значит хранить и передавать указатель на элемент справочника, документ или перечисление, а не сам объект. Ссылку получают через Объект.Ссылка, поиск (НайтиПоКоду, НайтиПоНаименованию) или запрос. Объект по ссылке открывают методом Ссылка.ПолучитьОбъект(), а пустоту проверяют ЗначениеЗаполнено().
Ссылка лёгкая: это тип объекта плюс уникальный идентификатор (УИД). Её можно положить в реквизит, передать с клиента на сервер, записать в регистр. Тема общая для платформы 8.3: всё ниже работает одинаково в Бухгалтерии 3.0, ЗУП 3.1, УТ 11 и самописных конфигурациях.
Что такое ссылка в 1С и чем она отличается от объекта
У каждого ссылочного объекта есть два представления:
- 🔗 Ссылка (
СправочникСсылка.Контрагенты) — только адрес записи в базе. Читать реквизиты через неё можно, менять нельзя. - 📦 Объект (
СправочникОбъект.Контрагенты) — полная копия записи в памяти. Его меняют и записывают методомЗаписать().
Ссылочные типы в 1С 8.3: справочники, документы, перечисления, планы видов характеристик, планы счетов, планы видов расчёта, бизнес-процессы, задачи, планы обмена. У регистров ссылок нет: запись регистра идентифицируют измерения и регистратор.
| Что нужно | Ссылка | Объект |
|---|---|---|
| Хранить в реквизите | ✅ | ❌ |
| Передать между клиентом и сервером | ✅ | ❌ (только через данные формы) |
| Прочитать реквизит | ✅ (на сервере) | ✅ |
| Изменить и записать | ❌ | ✅ |
| Затраты памяти | минимальные | вся запись с табличными частями |
Правило практика: всё, что только читает данные, работает со ссылкой или запросом. ПолучитьОбъект() вызывают, только когда объект действительно меняют.
Виды ссылок: заполненная, пустая, битая, навигационная
Термин «ссылка» в 1С встречается в четырёх смыслах. Путаница между ними — главный источник ошибок.
Заполненная ссылка
Указывает на существующую запись. Ссылка.Пустая() возвращает Ложь, ПолучитьОбъект() возвращает объект.
Пустая ссылка
Ссылка нужного типа без записи за ней. Новый реквизит типа «СправочникСсылка.Валюты» по умолчанию содержит именно её. Получить в коде:
ПустаяВалюта = Справочники.Валюты.ПустаяСсылка();
ПустойДокумент = Документы.РеализацияТоваровУслуг.ПустаяСсылка();
В запросе пустую ссылку задают так: ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка).
Битая ссылка
Ссылка с типом и УИД, но запись с таким УИД удалена. На форме она выглядит как <Объект не найден> (45:b8f1a2c3...): число — внутренний номер таблицы, дальше идентификатор. Ссылка.Пустая() для неё вернёт Ложь, а ПолучитьОбъект() — Неопределено.
Навигационная ссылка
Текстовый адрес формы или объекта, который понимают все клиенты 1С. Формат:
e1cib/data/Справочник.Контрагенты?ref=8f2e1a4b9c7d6e5f4a3b2c1d0e9f8a7b
В веб-клиенте перед ней добавляют адрес публикации: http://server/buh/#e1cib/data/.... Такую ссылку отправляют коллеге в мессенджере, и он открывает ту же карточку.
Как получить ссылку на объект в 1С
В коде
Основные способы с примерами:
// 1. Из объекта, который у вас уже есть
СсылкаНаДокумент = ДокументОбъект.Ссылка;
// 2. Поиском по коду или наименованию
Контрагент = Справочники.Контрагенты.НайтиПоКоду("00-000123");
Если Не ЗначениеЗаполнено(Контрагент) Тогда
// не нашли: метод вернул пустую ссылку, а не Неопределено
КонецЕсли;
// 3. Поиском по реквизиту
Контрагент = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", "7701234567");
// 4. Предопределённый элемент и значение перечисления
ВалютаРубль = Справочники.Валюты.НайтиПоКоду("643");
ВидКонтрагента = Перечисления.ЮридическоеФизическоеЛицо.ЮридическоеЛицо;
// 5. По известному УИД
УИД = Новый УникальныйИдентификатор("8f2e1a4b-9c7d-6e5f-4a3b-2c1d0e9f8a7b");
Контрагент = Справочники.Контрагенты.ПолучитьСсылку(УИД);
ПолучитьСсылку(УИД) не проверяет, есть ли запись в базе. Он просто собирает ссылку. Если объекта нет, вы получите битую ссылку. Проверка: Контрагент.ПолучитьОбъект() <> Неопределено или запрос по таблице.
Значение перечисления в примере условное: имена значений смотрите в конфигураторе, в дереве метаданных.
Для массовых выборок поиск по одной ссылке в цикле медленный. Лучше один запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН В (&СписокИНН)";
Запрос.УстановитьПараметр("СписокИНН", МассивИНН);
МассивСсылок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
В интерфейсе «Такси»
- Откройте карточку элемента или документа.
- В шапке формы нажмите значок со звеньями цепи — «Получить ссылку». Появится окно с навигационной ссылкой, её можно скопировать.
- Чтобы открыть чужую ссылку, в главном меню (кнопка с тремя полосками слева вверху) выберите «Перейти по ссылке» и вставьте строку.
Набор пунктов главного меню зависит от прав и настроек интерфейса. Если пункта нет, проверьте у администратора, не скрыт ли он.
Навигационная ссылка в коде
&НаСервере
Функция АдресКарточки(Ссылка)
Возврат ПолучитьНавигационнуюСсылку(Ссылка);
КонецФункции
&НаКлиенте
Процедура ОткрытьКарточку(Команда)
ПерейтиПоНавигационнойСсылке("e1cib/data/Справочник.Контрагенты?ref=8f2e1a4b9c7d6e5f4a3b2c1d0e9f8a7b");
КонецПроцедуры
Из ссылки можно вытащить УИД строкой: Строка(Ссылка.УникальныйИдентификатор()). Это удобно для логов и сопоставления с внешними системами.
Как создать объект по ссылке и на основании ссылки
Изменить существующий объект
Объект = Ссылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
ВызватьИсключение "Объект удалён: " + Строка(Ссылка.УникальныйИдентификатор());
КонецЕсли;
Объект.Комментарий = "Проверено";
Объект.Записать();
Проверка на Неопределено обязательна: без неё код упадёт на битой ссылке.
Создать новый объект с заданной ссылкой
Нужно при загрузке из другой базы, когда УИД должен совпасть:
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку(УИДИзФайла);
Если НоваяСсылка.ПолучитьОбъект() = Неопределено Тогда
Объект = Справочники.Контрагенты.СоздатьЭлемент();
Объект.УстановитьСсылкуНового(НоваяСсылка);
Объект.Наименование = НаименованиеИзФайла;
Объект.Записать();
КонецЕсли;
Если записи с таким УИД нет, но в базе на неё уже ссылаются документы, после записи битые ссылки «оживут»: они начнут указывать на новый элемент.
Ввод на основании
Документ-основание передают как ссылку в метод Заполнить():
НовыйСчет = Документы.СчетФактураВыданный.СоздатьДокумент();
НовыйСчет.Заполнить(СсылкаНаРеализацию);
Платформа вызовет обработчик ОбработкаЗаполнения модуля объекта, и в параметре ДанныеЗаполнения придёт ваша ссылка. Имя документа в примере условное: в каждой конфигурации своё.
Скопировать объект
Копия = Ссылка.ПолучитьОбъект().Скопировать();
Копия.Записать();
У копии своя новая ссылка. Табличные части копируются, а движения документа — нет.
Ссылки в запросах и составные типы
Через точку в запросе можно получить реквизит связанной таблицы: Реализация.Контрагент.ИНН. Платформа сама добавит левое соединение. Это удобно, но есть ловушка.
Составной тип и разыменование
Поле Регистратор у регистра может ссылаться на десятки видов документов. Обращение Регистратор.Дата заставит платформу соединить таблицу со всеми этими документами. На большой базе запрос замедлится в разы.
Решение — уточнить тип:
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Продажи.Регистратор КАК Документ.РеализацияТоваровУслуг).Номер КАК Номер
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|ГДЕ
| Продажи.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг"
Здесь ССЫЛКА отбирает строки нужного типа, а ВЫРАЗИТЬ ограничивает соединение одной таблицей. Имена регистра и документа замените своими.
Другие приёмы
- 🔎
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.ПоступлениеТоваровУслуг)— отбор по типу без разыменования. - 🧩
ЗНАЧЕНИЕ(Перечисление.ВидыКонтрагентов.ЮридическоеЛицо)— значение перечисления прямо в тексте запроса, без параметра. - 📄
ПРЕДСТАВЛЕНИЕ(Поле)— строковое представление ссылки, если оно нужно в отчёте, без лишних полей. - ⚡ В типовых конфигурациях на БСП реквизиты одной ссылки удобно читать функцией
ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН"), нескольких —ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, "ИНН, КПП").
Ссылки на клиенте
В тонком клиенте и веб-клиенте ссылку можно хранить и передавать, а вот прочитать её реквизит через точку нельзя. Контрагент.ИНН в процедуре &НаКлиенте вызовет ошибку. Читайте реквизит в серверной функции без контекста:
&НаСервереБезКонтекста
Функция ИННКонтрагента(Контрагент)
Возврат Контрагент.ИНН;
КонецФункции
Открыть форму по ссылке
Карточку объекта на клиенте открывают без навигационной строки: ссылку передают в параметр Ключ.
&НаКлиенте
Процедура ОткрытьКонтрагента(Контрагент)
ПараметрыФормы = Новый Структура("Ключ", Контрагент);
ОткрытьФорму("Справочник.Контрагенты.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
Короче то же самое делает ПоказатьЗначение(, Контрагент): платформа сама выберет основную форму объекта. Если карточка уже открыта, второй экземпляр не появится — активируется существующее окно.
Где ссылки встречаются в типовых конфигурациях
| Где | Какое поле | Что хранит |
|---|---|---|
| Документы БП 3.0 и УТ 11 | Контрагент, Договор, Организация | ссылки на справочники |
| Документы, введённые на основании | ДокументОснование или похожий реквизит | ссылка на документ-основание |
| Регистры накопления и сведений | Регистратор | ссылка на документ, сделавший движение |
| Табличные части | Номенклатура, Склад | ссылки на справочники |
| Обмены между базами | УИД ссылки | сопоставление одних и тех же элементов |
| Присоединённые файлы | ВладелецФайла | ссылка на документ или элемент |
Обмен между Бухгалтерией и УТ или ЗУП держится на том же механизме. Если в обеих базах у контрагента одинаковый УИД, правила обмена находят его без сопоставления по ИНН. Когда элемент создали руками в обеих базах, УИД разные — отсюда дубли после первой синхронизации.
Поле «Документ-основание» в форме — тоже ссылка. По ней в карточке документа строится структура подчинённости: цепочка «заказ → реализация → счёт-фактура».
Как найти битую ссылку и проверить, где используется объект
Где используется объект
Перед удалением элемента выясните, кто на него ссылается. В коде:
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(Контрагент);
Таблица = НайтиПоСсылкам(МассивСсылок);
// колонки: Ссылка (кого ищем), Данные (кто ссылается), Метаданные
Без кода — стандартная обработка «Поиск ссылок на объекты» в разделе Все функции → Стандартные. Если пункта «Все функции» нет, включите его: в главном меню Сервис → Параметры, флаг «Отображать команду «Все функции»».
Как починить битые ссылки
Перед исправлением сделайте резервную копию базы : выгрузку .dt или копию SQL.
Порядок действий:
- Выясните, что было удалено. Возьмите УИД из представления
<Объект не найден>и поищите запись в резервной копии. - Если объект нужен — восстановите его из копии с тем же УИД, как в примере с
УстановитьСсылкуНового. Битые ссылки станут нормальными. - Если массово — запустите
Конфигуратор → Администрирование → Тестирование и исправлениес флагом «Проверка ссылочной целостности». Для битых ссылок программа предложит варианты: создавать объекты-заглушки, очищать ссылки или не изменять.
Тестирование и исправление с исправлением ошибок требует монопольного доступа: всех пользователей придётся вывести из базы. Запускайте в нерабочее время. Вариант «Очищать ссылки» стирает реквизиты в документах навсегда, а «Создавать объекты» добавляет пустые элементы, которые потом нужно заполнить.
Отладка
В отладчике в окне «Вычислить выражение» проверяйте:
ТипЗнч(Ссылка)— какого типа значение на самом деле;Ссылка.Пустая()— пустая ли ссылка;Ссылка.ПолучитьОбъект() = Неопределено— не битая ли она;Ссылка.Метаданные().ПолноеИмя()— к какому объекту метаданных относится.
НайтиПоКоду и НайтиПоНаименованию не нашли запись. Проверьте префикс кода, лишние пробелы и родителя в иерархии.&НаСервереБезКонтекста.Регистратор. Добавьте ВЫРАЗИТЬ и отбор ССЫЛКА.Ошибки при работе со ссылками
- ❌ Сравнение с
Неопределеновместо проверки заполненности. Пустая ссылка не равнаНеопределено. ИспользуйтеЗначениеЗаполнено(Ссылка): функция ловит и пустую ссылку, иНеопределено. - ❌
ПолучитьОбъект()ради чтения одного реквизита. Объект грузится целиком с табличными частями. В цикле по тысяче документов это лишние минуты. - ❌ Удаление вместо пометки. Непосредственное удаление не проверяет ссылки — так и появляются битые. Помечайте на удаление и удаляйте через обработку удаления помеченных: она покажет, где объект ещё используется.
- ❌ Сборка навигационной ссылки руками. УИД в ней записан без дефисов и в особом порядке байтов. Строку берите только из
ПолучитьНавигационнуюСсылку(). - ❌ Хранение представления вместо ссылки. Наименование контрагента в строковом поле перестанет совпадать после переименования. Храните ссылку, представление получайте при выводе.
Можно ли хранить ссылку в константе или регистре сведений?
Меняется ли ссылка после переименования или изменения кода?
Сохранится ли ссылка при выгрузке и загрузке базы через .dt?
Как передать ссылку во внешнюю систему?
Строка(Ссылка.УникальныйИдентификатор()). Обратно ссылку собирают методом ПолучитьСсылку(Новый УникальныйИдентификатор(Строка)) и проверяют, что объект существует.Чем ссылка на элемент отличается от ссылки на группу справочника?
ЭтоГруппа, если справочник иерархический с группами.