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

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

Как выразить регистратор как документ в 1С

Как выразить регистратор как документ в 1С с помощью ВЫРАЗИТЬ в запросе, зачем это нужно, типовые ошибки и примеры кода для регистров накопления и сведений.

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

Задача «выразить регистратор как документ» возникает, когда нужно получить из движений регистра реквизиты документа-регистратора: контрагента, склад, дату, номер, организацию. Решается она двумя способами — оператором ВЫРАЗИТЬ в языке запросов или методом ПолучитьОбъект() / проверкой типа в коде. Правильный выбор зависит от того, где выполняется обработка данных.

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

Что такое регистратор и почему его нельзя использовать напрямую

Каждая запись регистра (накопления, сведений, бухгалтерии, расчёта) содержит служебное поле «Регистратор». В нём хранится ссылка на документ, сформировавший запись. Если регистр заполняется только одним видом документов, тип поля простой, и обращение Движения.Регистратор.Контрагент сработает без дополнительных действий.

На практике большинство регистров имеет несколько регистраторов. Например, регистр накопления «Товары на складах» заполняют «Поступление товаров», «Реализация товаров», «Перемещение», «Оприходование». Тип поля становится составным, и платформа запрещает «разыменование» через точку: у разных документов разный набор реквизитов, поэтому запрос вида ВЫБРАТЬ Движения.Регистратор.Контрагент завершится ошибкой ещё на этапе проверки.

Как выразить регистратор в запросе через ВЫРАЗИТЬ

Оператор ВЫРАЗИТЬ приводит значение составного типа к конкретному типу. Синтаксис для регистратора выглядит так:

ВЫБРАТЬ

Движения.Номенклатура,

ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваров) КАК ДокументПоступления,

ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваров).Контрагент КАК Контрагент

ИЗ

РегистрНакопления.ТоварыНаСкладах КАК Движения

ГДЕ

Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваров

Ключевые моменты конструкции:

  • условие Регистратор ССЫЛКА Документ.ПоступлениеТоваров отсекает записи других документов — без него ВЫРАЗИТЬ вернёт для них NULL;
  • после приведения типа к реквизитам документа обращаются через точку: .Контрагент, .Склад, .Номер;
  • если реквизит нужен в нескольких местах запроса, выгоднее один раз выразить регистратор в поле и дальше использовать псевдоним, а не повторять ВЫРАЗИТЬ.

Если нужны движения по двум видам документов, используют два выражения и функцию ЕСТЬNULL либо объединение через ОБЪЕДИНИТЬ ВСЕ с отдельным условием ССЫЛКА в каждой части.

Порядок действий в запросе
  1. 1
    Определите, какие виды документов являются регистраторами нужного регистра (свойства регистра, закладка «Регистраторы» в конфигураторе)
  2. 2
    Добавьте в запрос условие Регистратор ССЫЛКА Документ.ИмяДокумента
  3. 3
    Оберните поле регистратора в ВЫРАЗИТЬ(... КАК Документ.ИмяДокумента)
  4. 4
    Обратитесь к нужным реквизитам через точку после приведения типа
  5. 5
    Выполните запрос в консоли и проверьте, что поля реквизитов заполнены, а не NULL

Как выразить регистратор в коде модуля

В программном коде оператора ВЫРАЗИТЬ нет — вместо него проверяют тип значения и работают со ссылкой. Типовой приём:

Если ТипЗнч(Запись.Регистратор) = Тип("ДокументСсылка.ПоступлениеТоваров") Тогда

Контрагент = Запись.Регистратор.Контрагент;

КонецЕсли;

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

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

Выбор между запросом и кодом

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

КритерийВЫРАЗИТЬ в запросеПроверка типа в коде
Объём данныхБольшие выборки, тысячи записейЕдиничные записи, точечная логика
ПроизводительностьОдин запрос к СУБДРиск запроса на каждую итерацию
ГибкостьТолько чтение, декларативная логикаЛюбая логика, ветвления, изменение данных
Типовое применениеОтчёты, СКД, выгрузкиОбработчики, проведение, обмены

Для отчётов и аналитики однозначно выбирайте ВЫРАЗИТЬ: вся фильтрация и соединения выполняются на стороне СУБД. Для обработчиков проведения или единичных операций достаточно проверки ТипЗнч() в коде.

Маршрут решения

Как выбрать действие

Нужен отчёт или выборка по движениям с реквизитами документовИспользуйте ВЫРАЗИТЬ в запросе с условием ССЫЛКА
Нужно обработать одну запись или проверить вид регистратора в обработчикеПроверьте тип через ТипЗнч() и читайте реквизиты по ссылке
Регистраторов несколько видов и нужны их общие реквизиты (дата, номер)Обращайтесь к стандартным реквизитам Дата и Номер напрямую — они есть у любого документа, ВЫРАЗИТЬ не требуется

Типичные ошибки и как их избежать

Самая частая ошибка — забыть условие ССЫЛКА и получить NULL в реквизитах для «чужих» документов. Внешне запрос выполняется без ошибок, поэтому проблему замечают поздно, когда в отчёте пустые контрагенты. Второй симптом той же ошибки — соединение по выраженному регистратору, которое «теряет» строки.

Вторая группа ошибок связана с производительностью: ВЫРАЗИТЬ применяют к полю, по которому идёт соединение больших таблиц, без предварительного отбора. Оптимизатору тяжелее строить план по вычисляемому выражению, поэтому сначала отберите записи условием ССЫЛКА во временную таблицу, а приведение типа делайте уже к ней.

Типичные ошибки
01
ВЫРАЗИТЬ без условия ССЫЛКА — в реквизитах документов других видов появляется NULL, отчёт молча теряет данные
02
Обращение к реквизиту, которого нет у выбранного вида документа, — ошибка проверки запроса при выполнении
03
Чтение реквизитов регистратора через точку в цикле по записям — отдельный запрос к базе на каждой итерации
04
Попытка выразить регистратор как справочник — ВЫРАЗИТЬ приводит только к реальному типу значения, иначе результат NULL
05
Использование ПолучитьОбъект() ради чтения одного реквизита — лишнее вычитывание всего документа с табличными частями

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

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

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

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

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

Колонка с ВЫРАЗИТЬ в результате запроса
Норма

Заполнена ссылками нужного вида документа

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

NULL или ссылки других видов

Реквизиты документа через точку
Норма

Значения соответствуют данным документов

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

Пустые значения при заполненных документах

Скорость обработки в цикле
Норма

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

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

Запрос к базе на каждой итерации цикла

FAQ

Можно ли обратиться к реквизитам регистратора без ВЫРАЗИТЬ?

Да, но только к стандартным реквизитам, общим для всех документов: Дата, Номер, Проведён. Они доступны через точку даже при составном типе. Для прикладных реквизитов (Контрагент, Склад, Договор) приведение типа через ВЫРАЗИТЬ обязательно.

Что вернёт ВЫРАЗИТЬ, если регистратор — документ другого вида?

Оператор вернёт NULL, а обращение к реквизиту через точку даст NULL без ошибки выполнения. Поэтому условие ССЫЛКА в запросе обязательно — оно отсекает такие записи на уровне выборки, а не оставляет их с пустыми полями.

Работает ли ВЫРАЗИТЬ с регистратором в СКД?

Да, в наборе данных схемы компоновки работает тот же язык запросов, включая ВЫРАЗИТЬ и ССЫЛКА. Типовой приём — выразить регистратор в поле набора данных, а реквизиты документа вытащить через точку уже в выбранных полях отчёта.

Как в запросе получить движения сразу по двум видам регистраторов?

Используйте ОБЪЕДИНИТЬ ВСЕ двух выборок, в каждой — своё условие ССЫЛКА и своё ВЫРАЗИТЬ. Альтернатива — одна выборка с условием «ССЫЛКА первый ИЛИ ССЫЛКА второй» и извлечением реквизитов через ЕСТЬNULL(ВЫРАЗИТЬ(...КАК Первый).Реквизит, ВЫРАЗИТЬ(...КАК Второй).Реквизит).

Почему запрос с ВЫРАЗИТЬ работает медленно?

Чаще всего приведение типа применяется до отбора данных или участвует в соединении больших таблиц. Сначала поместите во временную таблицу записи, отфильтрованные условием ССЫЛКА и периодом, а ВЫРАЗИТЬ применяйте уже к этой сокращённой выборке — план запроса станет заметно легче.

Итог

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

Регистратор с составным типом приводится к конкретному документу оператором ВЫРАЗИТЬ в запросе или проверкой ТипЗнч() в коде. Всегда сопровождайте приведение условием ССЫЛКА, не читайте реквизиты по ссылке внутри больших циклов и проверяйте результат на NULL в консоли запросов.