Как скопировать ХранилищеЗначения при копировании элемента справочника в 1С

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

При работе с конфигурациями на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с особенностью поведения системы: при интерактивном или программном копировании объекта реквизиты с типом ХранилищеЗначения автоматически очищаются. Это стандартное поведение платформы, предназначенное для предотвращения неявного дублирования «тяжелых» данных, таких как файлы, картинки или сложные настройки. Однако в ряде случаев, например, в справочнике тарифов УАТ (Управление автотранспортом), где в хранилище находятся настройки компоновки данных (отборы), это становится проблемой. Рассмотрим, как правильно реализовать механизм копирования таких данных.

Анализ проблемы и выбор событий

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

Для решения задачи нам доступны два основных инструмента:

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

Реализация логики в модуле объекта

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

Рассмотрим пример кода, который необходимо разместить в модуле справочника:


Процедура ПриКопировании(ОбъектКопирования)
    
    // Проверяем, что копируется не группа (если справочник иерархический)
    Если Не ЭтоГруппа Тогда
        
        // Извлекаем значение из хранилища объекта-источника
        // ХранилищеЗначения нельзя присвоить напрямую, нужно получить его содержимое
        ДанныеХранилища = ОбъектКопирования.ОбластьДействия.Получить();
        
        // Если в источнике были данные, создаем новое хранилище для текущего объекта
        Если ДанныеХранилища <> Неопределено Тогда
            ОбластьДействия = Новый ХранилищеЗначения(ДанныеХранилища);
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Почему форма может оставаться пустой?

Часто возникает ситуация, когда код в ПриКопировании отработал верно, но при открытии формы нового элемента пользователь видит пустые поля (например, пустую область действия тарифа). Разберем причины этого явления. В сложных конфигурациях, таких как УАТ, данные из ХранилищаЗначения не отображаются на форме напрямую. Вместо этого они считываются при открытии и загружаются в Компоновщик настроек (вспомогательный объект на форме).

Если в форме предусмотрена сложная инициализация, она может перезаписывать данные, которые вы программно заполнили в модуле объекта. Чтобы этого избежать, проанализируем модуль формы.

Реализация логики в модуле формы

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

Рассмотрим, как это можно реализовать:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем, открыта ли форма для создания нового элемента путем копирования
    Если Параметры.Ключ.Пустая() И Не Параметры.ЗначениеКопирования.Пустая() Тогда
        
        // Параметры.ЗначениеКопирования содержит ссылку на исходный объект
        ОбъектИсточник = Параметры.ЗначениеКопирования;
        
        // Получаем настройки из хранилища источника
        НастройкиИзХранилища = ОбъектИсточник.ОбластьДействия.Получить();
        
        Если НастройкиИзХранилища <> Неопределено Тогда
            // Если на форме есть компоновщик настроек (типовой прием для отборов),
            // загружаем настройки в него
            ЭтаФорма.КомпоновщикНастроекОбластиДействия.ЗагрузитьНастройки(НастройкиИзХранилища);
            
            // Также не забываем обновить сам объект, если это требуется логикой формы
            Объект.ОбластьДействия = Новый ХранилищеЗначения(НастройкиИзХранилища);
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Оптимизация хранения данных

В ходе обсуждения темы был предложен альтернативный архитектурный подход: вместо хранения ХранилищаЗначения непосредственно в реквизите каждого тарифа, завести отдельный справочник (например, Справочник.Файлы или Справочник.НастройкиОбластейДействия). В таком случае в основном справочнике тарифов будет храниться просто ссылка.

Преимущества такого подхода:

  1. Экономия места: если у нескольких тарифов одинаковая область действия, они могут ссылаться на один и тот же элемент вспомогательного справочника.
  2. Простота копирования: ссылка — это простой тип данных, она копируется платформой автоматически, и вам не придется писать дополнительный код для переноса ХранилищаЗначения.
  3. Производительность: основная таблица справочника не будет «раздуваться» от бинарных данных, что ускорит выборки и отчеты.

Итоги

Подведем итог. Для копирования ХранилищаЗначения мы выяснили следующее:

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

← На главную