Как правильно хранить и отображать ссылки на документы, созданные на основании

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

В процессе разработки на платформе 1С:Предприятие 8.3 (особенно в рамках обычного приложения) часто возникает задача: при создании одного документа на основании другого необходимо иметь возможность быстро отследить эту связь. Начинающие разработчики часто пытаются решить эту задачу «в лоб» — добавить в исходный документ Д1 реквизит или табличную часть, чтобы хранить там ссылку на созданный документ Д2. Однако такой подход противоречит архитектуре 1С и ведет к ряду технических проблем.

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

Архитектурный принцип связи документов в 1С

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

Рассмотрим, какие инструменты позволяют нам реализовать обратную связь, не нарушая этих принципов.

Решение 1. Использование критериев отбора

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

Разберем реализацию по шагам:

  1. В конфигураторе создадим новый объект КритерийОтбора (например, СвязанныеДокументы).
  2. На вкладке Данные укажем тип — ДокументСсылка (выберем все типы документов, которые могут выступать основаниями).
  3. На вкладке Состав отметим реквизиты подчиненных документов (например, Д2.ДокументОснование, Д3.Основание и т.д.).

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

Решение 2. Программное получение ссылки через УстановитьСсылкуНового()

Иногда требуется получить ссылку на документ Д2 еще до того, как он был записан в базу данных. Это актуально в момент выполнения процедуры ОбработкаЗаполнения. Рассмотрим, как это реализовать. В модуле документа Д2 мы можем явно инициализировать ссылку:


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

Важное предостережение: если вы решите записать эту НовуюСсылку в исходный документ Д1, помните о риске. Если пользователь закроет форму Д2 без сохранения, в документе Д1 останется «битая» ссылка, указывающая на объект, которого не существует в базе.

Решение 3. Быстрый поиск через запросы

Если нам нужно в списке документов Д1 видеть информацию о наличии созданных Д2, оптимальным решением будет использование запроса. Выясним причину, по которой это лучше перебора: запрос работает на уровне сервера СУБД и использует индексы по реквизиту ДокументОснование.

Посмотрим на пример запроса, который выбирает все Д1, для которых еще НЕ созданы документы Д2:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Д1.Ссылка КАК ДокументОснование
    |ИЗ
    |	Документ.Д1 КАК Д1
    |ЛЕВОЕ СОЕДИНЕНИЕ Документ.Д2 КАК Д2
    |	ПО Д1.Ссылка = Д2.ДокументОснование
    |ГДЕ
    |	Д2.Ссылка ЕСТЬ NULL";

РезультатЗапроса = Запрос.Выполнить();

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

Почему хранение ссылок в документе-основании — это плохая практика?

Проанализируем ситуацию, когда разработчик все же решает добавить табличную часть в Д1 для хранения ссылок на Д2. Выделим основные проблемы такого подхода:

  1. Блокировки данных: При создании Д2 вам придется записывать и проводить Д1. Если в этот момент другой пользователь редактирует Д1, возникнет конфликт блокировок.
  2. Права доступа: У бухгалтера может быть право на создание Д2, но запрет на изменение Д1 (например, если период закрыт). Ваша схема просто не сработает.
  3. История изменений: Каждая запись ссылки в Д1 будет создавать новую версию документа в журнале регистрации и менять дату его изменения, что затрудняет аудит.
  4. Целостность: При удалении или отмене проведения Д2 вам придется писать сложный код для «вычистки» ссылок из Д1.

Использование вспомогательного регистра сведений

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

В этом случае в момент записи документа Д2 создается запись в регистре с измерениями ДокументОснование и ПодчиненныйДокумент. Это позволяет сохранить связь, не меняя сами документы и обходя проблемы с правами доступа к закрытым периодам.

Резюмируем: Для решения задачи отображения связей «на лету» используйте запросы и критерии отбора. Храните ссылку только в подчиненном документе. Это обеспечит стабильность и высокую скорость работы вашей конфигурации.

← На главную