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

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

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

Метод 1. Алгоритм синхронизации в событии ПередЗаписью

Рассмотрим стандартный подход через модуль объекта. Чтобы избежать простого добавления строк (которое и ведет к дублированию), нам необходимо реализовать алгоритм «сопоставления». Вместо того чтобы просто очищать таблицу и записывать её заново (что может привести к потере ссылок на строки ТЧ, если они используются где-то еще), мы проанализируем текущий состав и внесем только необходимые изменения.

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если объект новый, то ссылки еще нет, заполнение может не иметь смысла
    Если ЭтоНовый() Тогда
        Возврат;
    КонецЕсли;

    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВнешнееОборудование.Назначение КАК Назначение,
    |	ВнешнееОборудование.ТипОборудования КАК ТипОборудования,
    |	ВнешнееОборудование.SN КАК SN,
    |	ВнешнееОборудование.Ссылка КАК ОбъектИсточник
    |ИЗ
    |	Справочник.ВнешнееОборудование КАК ВнешнееОборудование
    |ГДЕ
    |	ВнешнееОборудование.Name = &ТекущаяСтанция
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |
    |ВЫБРАТЬ
    |	СиловоеОборудование.Назначение,
    |	СиловоеОборудование.ТипОборудования,
    |	СиловоеОборудование.SN,
    |	СиловоеОборудование.Ссылка
    |ИЗ
    |	Справочник.СиловоеОборудование КАК СиловоеОборудование
    |ГДЕ
    |	СиловоеОборудование.Name = &ТекущаяСтанция";

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

КонецПроцедуры

В этом примере мы используем оператор ОБЪЕДИНИТЬ ВСЕ, что позволяет получить данные из пяти и более справочников за один вызов сервера. Обратите внимание на поле ОбъектИсточник — это ключевой момент для предотвращения дублей.

Метод 2. Использование ключа связи для точного сопоставления

Выясним причину, по которой обычное сравнение по полям «Назначение» или «Серийный номер» может давать сбои. Данные в справочниках-источниках могут меняться, и только ссылка на конкретный элемент (объект-источник) гарантирует нам точность сопоставления. Рекомендуем добавить в табличную часть УстановленноеОборудование скрытый реквизит ОбъектИсточник с типом ЛюбаяСсылка.

Разберем процедуру СинхронизироватьТабличнуюЧасть, которая будет сравнивать то, что уже есть в ТЧ, с тем, что мы получили из запроса:


Процедура СинхронизироватьТабличнуюЧасть(АктуальныеДанные)
    
    // 1. Удаляем строки, которых больше нет в источниках
    Индекс = УстановленноеОборудование.Количество() - 1;
    Пока Индекс >= 0 Цикл
        СтрокаТЧ = УстановленноеОборудование[Индекс];
        Если АктуальныеДанные.Найти(СтрокаТЧ.ОбъектИсточник, "ОбъектИсточник") = Неопределено Тогда
            УстановленноеОборудование.Удалить(СтрокаТЧ);
        КонецЕсли;
        Индекс = Индекс - 1;
    КонецЦикла;

    // 2. Обновляем существующие и добавляем новые
    Для Каждого СтрокаИсточник Из АктуальныеДанные Цикл
        ПараметрыПоиска = Новый Структура("ОбъектИсточник", СтрокаИсточник.ОбъектИсточник);
        НайденныеСтроки = УстановленноеОборудование.НайтиСтроки(ПараметрыПоиска);
        
        Если НайденныеСтроки.Количество() > 0 Тогда
            // Обновляем реквизиты, если они изменились в источнике
            ЗаполнитьЗначенияСвойств(НайденныеСтроки[0], СтрокаИсточник);
        Иначе
            // Добавляем новую строку
            НоваяСтрока = УстановленноеОборудование.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточник);
        КонецЕсли;
    КонецЦикла;

КонецПроцедуры

Такой подход полностью исключает дублирование, так как система всегда знает, какая строка ТЧ соответствует конкретному прибору в базе. Метод ЗаполнитьЗначенияСвойств значительно сокращает код, автоматически копируя данные из колонок ТЗ в колонки ТЧ с одинаковыми именами.

Метод 3. Архитектурная альтернатива — Регистры сведений

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

Вместо хранения данных в табличной части справочника, мы создаем непериодический регистр сведений СоставРабочихСтанций с измерениями:

  1. РабочаяСтанция (СправочникСсылка.РабочиеСтанции)
  2. Оборудование (ЛюбаяСсылка)

В этом случае уникальность записей контролируется самой платформой 1С на уровне ключа регистра. На форму справочника РабочиеСтанции мы просто выносим Динамический список с отбором по текущей ссылке. Это избавляет нас от необходимости писать сложный код синхронизации в ПередЗаписью.

Метод 4. Интерактивное заполнение через форму

Посмотрим на проблему со стороны пользователя. Если мы заполняем ТЧ только в ПередЗаписью, пользователь не увидит изменений, пока не нажмет кнопку «Записать». Это может сбивать с толку. Рассмотрим вариант создания кнопки «Обновить состав» на форме.

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

Важные моменты для запоминания:

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

← На главную