Как найти запись регистра сведений и почему метод НайтиПоСсылкам не подходит для решения этой задачи

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

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

1. Суть проблемы и разбор практической ситуации

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

В процессе обсуждения коллеги справедливо указывают на важнейшую особенность платформы: регистр сведений не является ссылочной сущностью. У него отсутствует уникальный идентификатор (GUID), который есть у справочников, документов или бизнес-процессов. Следовательно, получить прямую ссылку на саму «строку» регистра невозможно, как невозможно и натравить на нее стандартные механизмы поиска ссылок. Для сопоставления объектов в условиях, когда ссылки в базах не совпадают, применяется перенос данных между похожими конфигурациями 1С по произвольным полям.

2. Как устроен регистр сведений в контексте ссылочной целостности

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

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

3. Особенности работы метода НайтиПоСсылкам() с регистрами сведений

Многие разработчики ошибочно полагают, что метод НайтиПоСсылкам() полностью игнорирует регистры. Это не так. Платформа действительно умеет анализировать таблицы регистров сведений при поиске ссылок на физические объекты (например, на элементы справочников или документы). Рассмотрим этот механизм подробнее:

  1. Метод НайтиПоСсылкам() сканирует измерения, ресурсы и реквизиты регистров сведений в поисках переданной ему ссылки (например, конкретного сотрудника).
  2. Если ссылка найдена в одной из строк регистра, метод возвращает результат. При этом в результирующей таблице значений в колонке «Данные» будет содержаться именно РегистрСведенийКлючЗаписи, а не сам регистр или его менеджер.
  3. При этом регистры накопления, регистры бухгалтерии и регистры расчета данным методом полностью игнорируются, так как они работают исключительно в связке с документами-регистраторами.

Посмотрим на пример использования метода НайтиПоСсылкам() для анализа того, где в регистрах задействован конкретный объект:


МассивИскомых = Новый Массив;
МассивИскомых.Добавить(СсылкаНаСотрудника);

ОбластьПоиска = Новый Массив; // Пустой массив означает поиск по всей базе
ВключаемыеОбъекты = Новый Массив;
ВключаемыеОбъекты.Добавить(Метаданные.РегистрыСведений.ИсторияИзмененияОбъектов);

ТаблицаСсылок = НайтиПоСсылкам(МассивИскомых, ОбластьПоиска, ВключаемыеОбъекты);

В результате выполнения этого кода мы получим таблицу, строки которой будут указывать на конкретные ключи записей регистра. Но этот метод решает обратную задачу: он ищет, где используется уже известная нам ссылка. В задаче автора темы ситуация противоположная: сама ссылка на сотрудника неизвестна, а известны лишь параметры (аналитика) внутри регистра.

4. Почему метод НайтиПоСсылкам() нельзя использовать в бизнес-логике

Использование метода НайтиПоСсылкам() для оперативного поиска данных в коде конфигурации — это грубейшая ошибка проектирования по следующим причинам:

5. Единственно верное решение — использование Запросов

Для поиска любой информации в регистрах сведений по известным параметрам (измерениям, ресурсам или реквизитам) всегда следует использовать Запросы. Это позволяет СУБД использовать наиболее оптимальные индексы таблиц БД, моментально возвращая точный результат.

Разберем по шагам, как решить задачу автора темы. Нам необходимо найти сотрудника, у которого была установлена определенная тарифная ставка в разрезе подразделения и должности. Если регистр сведений является периодическим (например, хранит историю ставок во времени), нам потребуется обратиться к виртуальной таблице СрезПоследних.

Проанализируем пример кода с использованием оптимального запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ШтатноеРасписаниеСрезПоследних.Сотрудник КАК Сотрудник,
    |	ШтатноеРасписаниеСрезПоследних.Подразделение КАК Подразделение,
    |	ШтатноеРасписаниеСрезПоследних.Должность КАК Должность,
    |	ШтатноеРасписаниеСрезПоследних.ТарифнаяСтавка КАК ТарифнаяСтавка
    |ИЗ
    |	РегистрСведений.ИсторияШтатногоРасписания.СрезПоследних(&Период, ) КАК ШтатноеРасписаниеСрезПоследних
    |ГДЕ
    |	ШтатноеРасписаниеСрезПоследних.Подразделение = &Подразделение
    |	И ШтатноеРасписаниеСрезПоследних.Должность = &Должность
    |	И ШтатноеРасписаниеСрезПоследних.ТарифнаяСтавка = &ТарифнаяСтавка";

// Установка параметров запроса
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("Подразделение", ВыбранноеПодразделение);
Запрос.УстановитьПараметр("Должность", ВыбраннаяДолжность);
Запрос.УстановитьПараметр("ТарифнаяСтавка", ИскомаяСтавка);

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

Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        Сообщить("Найден сотрудник: " + Выборка.Сотрудник + " на ставке " + Выборка.ТарифнаяСтавка);
    КонецЦикла;
Иначе
    Сообщить("Записей, соответствующих указанным критериям, не найдено.");
КонецЕсли;

Данный запрос отработает за считанные миллисекунды даже на базах данных объемом в несколько терабайт, поскольку СУБД использует индексы по измерениям регистра сведений.

6. Как изменить или удалить запись регистра сведений, полученную из поиска ссылок

Что делать, если в рамках другой задачи (например, при написании универсальной обработки очистки битых ссылок) мы все же использовали метод НайтиПоСсылкам() и получили на входе массив объектов типа РегистрСведенийКлючЗаписи? Напрямую изменить или удалить строку через этот объект нельзя, так как он предназначен исключительно для идентификации. Для автоматизации подобных операций можно использовать утилиту для поиска и удаления записей с битыми ссылками в регистрах.

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

  1. Создаем пустой менеджер записи нужного регистра сведений.
  2. Переносим значения ключевых параметров из ключа записи в менеджер записи (для этого идеально подходит стандартная функция ЗаполнитьЗначенияСвойств()).
  3. Вызываем метод Прочитать(), чтобы считать текущие данные из базы.
  4. Выполняем требуемые изменения ресурсов или реквизитов и вызываем метод Записать() (или метод Удалить(), если запись требуется стереть из системы).

Посмотрим на практическую реализацию этого алгоритма в коде:


// Предположим, КлючЗаписи был получен в результате работы НайтиПоСсылкам()
Если ТипЗнч(КлючЗаписи) = Тип("РегистрСведенийКлючЗаписи.ИсторияИзмененияОбъектов") Тогда
    
    // 1. Создаем менеджер записи
    МенеджерЗаписи = РегистрыСведений.ИсторияИзмененияОбъектов.СоздатьМенеджерЗаписи();
    
    // 2. Копируем ключевые поля
    ЗаполнитьЗначенияСвойств(МенеджерЗаписи, КлючЗаписи);
    
    // 3. Читаем существующую запись
    МенеджерЗаписи.Прочитать();
    
    Если МенеджерЗаписи.Выбран() Тогда
        // 4. Выполняем требуемое действие (например, удаление записи)
        МенеджерЗаписи.Удалить();
        Сообщить("Запись успешно удалена из регистра.");
    КонецЕсли;
    
КонецЕсли;

7. Полезные механизмы современных версий платформы 1С

Разработчикам универсальных механизмов и инструментов администрирования баз данных полезно знать о двух важных улучшениях платформы 1С:

8. Резюме

Подводя итоги нашего анализа, зафиксируем ключевые правила работы с поиском в регистрах сведений:

  1. Никогда не пытайтесь получить ссылку на строку регистра сведений — ее не существует в архитектуре 1С.
  2. Используйте метод НайтиПоСсылкам() исключительно для служебных целей, например для проверки возможности удаления элементов справочников, так как данный метод создает колоссальную нагрузку на систему.
  3. Для решения любых бизнес-задач по поиску информации внутри регистров всегда используйте Запросы с явным указанием отборов по индексируемым полям (измерениям). Это гарантирует быструю и стабильную работу вашего программного кода.
← На главную