К статье
Практический материал

Разработка и Конфигурация · 11 мин

1С: как обратиться к документу по ссылке

Как в 1С обратиться к документу по ссылке: методы ПолучитьОбъект, проверка ссылки, работа с реквизитами, типичные ошибки и примеры кода для разработчиков.

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

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

Ниже разобраны основные способы обращения к документу по ссылке: чтение реквизитов, получение объекта для редактирования, проверка корректности ссылки, работа с табличными частями и типичные ошибки, которые приводят к падению производительности или ошибкам времени выполнения.

Что такое ссылка на документ и чем она отличается от объекта

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

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

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

Самый простой способ обращения — точечная нотация. Если у вас есть переменная со ссылкой, реквизиты доступны напрямую:

НомерДокумента = ДокументСсылка.Номер;

ДатаДокумента = ДокументСсылка.Дата;

Контрагент = ДокументСсылка.Контрагент;

Сумма = ДокументСсылка.СуммаДокумента;

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

Для чтения нескольких реквизитов у множества документов правильнее использовать запрос с конструкцией ВЫБРАТЬ ... ИЗ Документ.ИмяДокумента ГДЕ Ссылка В (&СписокСсылок). Один запрос вернёт все нужные данные выборкой, что на порядки быстрее циклического разыменования.

Как получить объект документа для изменения данных

Когда требуется изменить документ — поправить реквизит, добавить строку в табличную часть, перепровести, — используется метод ПолучитьОбъект(). Он загружает документ из базы в память целиком:

ДокументОбъект = ДокументСсылка.ПолучитьОбъект();

ДокументОбъект.Комментарий = "Скорректировано обработкой";

ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

После изменений объект обязательно нужно записать явным вызовом Записать() — без этого изменения потеряются. Режим записи выбирается по задаче: Запись для простого сохранения, Проведение для проведения документа, ОтменаПроведения для распроведения.

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

Как проверить ссылку: пустая, битая или существующая

Прежде чем работать со ссылкой, её нужно проверить. Типовая цепочка проверок выглядит так: сначала проверка на пустую ссылку, затем — на реальное существование документа в базе.

Если ДокументСсылка.Пустая() Тогда

Возврат; // ссылка не заполнена

КонецЕсли;

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Документ.РеализацияТоваровУслуг ГДЕ Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);

Если Запрос.Выполнить().Пустой() Тогда

Возврат; // документ удалён — битая ссылка

КонецЕсли;

Битая ссылка возникает, когда документ был физически удалён, а ссылки на него остались в других объектах или регистрах. При обращении к реквизитам такой ссылки платформа вернёт значения по умолчанию, а при попытке ПолучитьОбъект() будет получено значение Неопределено — это тоже стоит проверять.

Дополнительно полезна проверка типа ссылки, если переменная может содержать документы разных видов: Если ТипЗнч(Ссылка) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда .... Это защищает код от ошибок при обращении к несуществующим реквизитам другого вида документа.

Порядок безопасного обращения к документу
  1. 1
    Проверьте ссылку методом Пустая()
  2. 2
    Убедитесь, что тип ссылки соответствует ожидаемому виду документа
  3. 3
    Проверьте существование документа запросом или через ПолучитьОбъект() с проверкой на Неопределено
  4. 4
    Для чтения используйте разыменование или запрос, для изменения — ПолучитьОбъект() и Записать()
  5. 5
    Обработайте возможные исключения блокировки при записи

Как получить ссылку по номеру, дате или из другого объекта

На практике ссылка чаще всего приходит «снаружи»: из реквизита другого документа, из результата запроса, из параметра формы. Но если у вас есть только номер документа, ссылку можно найти методом менеджера документа:

Ссылка = Документы.РеализацияТоваровУслуг.НайтиПоНомеру("0000-000123", ТекущаяДатаСеанса());

Если Ссылка.Пустая() Тогда

Сообщить("Документ не найден");

КонецЕсли;

Метод НайтиПоНомеру требует указания даты — она определяет период поиска, потому что нумерация документов обычно периодическая. Если номер не найден, возвращается пустая ссылка, а не исключение.

Ещё один сценарий — получение ссылки из уникального идентификатора. Это нужно при обмене данными, когда идентификатор приходит из внешней системы строкой:

УИД = Новый УникальныйИдентификатор("a1b2c3d4-...");

Ссылка = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(УИД);

Обратите внимание: ПолучитьСсылку конструирует ссылку из идентификатора, но не проверяет, существует ли такой документ реально. Результат может оказаться битой ссылкой, поэтому дальнейшая проверка существования обязательна.

Сравнение способов получения данных

Разыменование (Ссылка.Реквизит)

Подходит для чтения 1–2 реквизитов одного документа. Ограничение: отдельное обращение к базе на каждый реквизит, медленно в циклах.

Запрос к таблице документа

Оптимален для чтения данных по многим документам. Ограничение: только чтение, изменить данные нельзя.

ПолучитьОбъект()

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

НайтиПоНомеру / ПолучитьСсылку

Способы получить саму ссылку по известным данным. Ограничение: не гарантируют существование документа.

Работа с табличными частями через ссылку

Табличные части доступны через ссылку так же, как обычные реквизиты: обращение Ссылка.Товары возвращает табличную часть, по которой можно пройтись циклом и прочитать строки. Это работает, но каждое такое обращение — отдельный запрос к базе.

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

Запрос.Текст = "ВЫБРАТЬ Ссылка, Номенклатура, Количество

|ИЗ Документ.РеализацияТоваровУслуг.Товары

|ГДЕ Ссылка = &Ссылка";

Изменить табличную часть через ссылку нельзя — только через объект. После ПолучитьОбъект() табличная часть доступна как коллекция: можно добавлять строки методом Добавить(), удалять, изменять значения колонок, а затем записывать документ.

Типичные ошибки
01
Чтение реквизитов через точку внутри цикла по тысячам ссылок — резкое падение производительности из-за запросов в цикле
02
Вызов ПолучитьОбъект() без проверки результата на Неопределено — ошибка выполнения при битой ссылке
03
Изменение объекта без вызова Записать() — изменения молча теряются
04
Использование ПолучитьСсылку() как проверки существования — метод лишь конструирует ссылку, документа может не быть
05
Запись документа без обработки исключений — падение обработки при конфликте блокировок

Как проверить результат и отладить код

Проверить корректность обращения к документу проще всего в конфигураторе через отладку: поставьте точку останова после получения ссылки и посмотрите её значение в табло. У корректной ссылки отображается представление документа (вид, номер, дата), у битой — строка вида «Объект не найден» с идентификатором.

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

Если код работает медленно, включите замер производительности в конфигураторе: он покажет, сколько раз выполняется обращение к базе. Резкое преобладание строк с разыменованием ссылок — верный признак того, что код нужно переписать на запросы.

Контрольные точки

Как проверить результат

Значение ссылки в отладчике
Норма

Отображается вид, номер и дата документа

Тревожный признак

Строка «Объект не найден» — битая ссылка

Результат ПолучитьОбъект()
Норма

Возвращён объект, доступны реквизиты

Тревожный признак

Возвращено Неопределено — документа нет в базе

Записать() после изменений
Норма

Выполняется без исключений, изменения видны в базе

Тревожный признак

Ошибка блокировки или молчаливая потеря изменений

Производительность цикла
Норма

Один запрос на всю выборку данных

Тревожный признак

Замер показывает тысячи обращений к базе

Часто задаваемые вопросы

Чем ссылка отличается от объекта документа?

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

Можно ли изменить документ, не получая объект?

Нет, встроенный язык не позволяет изменять данные через ссылку. Единственный штатный способ изменения — ПолучитьОбъект(), внесение правок и Записать(). Альтернатива для массовых операций — обмен данными или прямые механизмы платформы, но это уже специализированные сценарии.

Что вернёт ПолучитьОбъект() для удалённого документа?

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

Как узнать, какие объекты ссылаются на документ?

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

Почему обращение Ссылка.Номер работает медленно в цикле?

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

Как получить ссылку на новый, ещё не записанный документ?

Создайте объект через Документы.ИмяДокумента.СоздатьДокумент(), затем вызовите УстановитьСсылкуНового() с заранее полученной ссылкой либо запишите документ — после записи ссылка доступна через свойство Ссылка объекта.

Итог

Что важно запомнить

Ссылка — для чтения, объект — для изменения. Перед работой проверяйте ссылку на пустоту и существование документа, результат ПолучитьОбъект() — на Неопределено. В циклах и массовых обработках заменяйте разыменование запросами, а запись объектов сопровождайте обработкой исключений.