В процессе разработки на платформе 1С часто возникает задача дублирования или выноса данных из табличной части справочника в независимый или подчиненный регистр сведений. Это может быть необходимо для построения отчетов, хранения истории изменений или связи данных с другими объектами системы. В этой статье мы подробно разберем, как правильно организовать этот процесс, какие инструменты использовать и каких ошибок стоит избегать.
Представим, что у нас есть справочник с табличной частью РегистрРесурсы. Нам необходимо, чтобы при записи справочника все строки из этой таблицы попадали в регистр сведений ТестовыйРегистр. Основная сложность для начинающих разработчиков заключается в правильной передаче ссылок, сопоставлении типов данных и выборе оптимального метода записи в базу данных.
Разберем основные подходы, начиная от самых простых и заканчивая наиболее эффективными с точки зрения производительности системы.
Этот метод часто выбирают новички, так как он кажется интуитивно понятным. Мы перебираем строки табличной части и для каждой создаем отдельный объект записи регистра. Проанализируем пример кода, который часто встречается в подобных задачах:
Процедура ПередЗаписью(Отказ)
Для каждого СтрокаРегистра Из РегистрРесурсы Цикл
НоваяЗапись = РегистрыСведений.ТестовыйРегистр.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(НоваяЗапись, СтрокаРегистра);
НоваяЗапись.Наименование = Ссылка; // Записываем ссылку на текущий справочник
НоваяЗапись.Записать();
КонецЦикла;
КонецПроцедуры
В данном примере мы используем метод ЗаполнитьЗначенияСвойств. Это очень удобная функция, которая автоматически копирует данные из колонок табличной части в одноименные измерения или ресурсы регистра. Однако у этого метода есть существенный минус: если в табличной части 100 строк, система выполнит 100 отдельных транзакций записи, что крайне негативно сказывается на быстродействии.
Для профессиональной разработки рекомендуется использовать НаборЗаписей. Это позволяет записать все изменения одним пакетом. Кроме того, использование набора данных с установленным отбором позволяет автоматически очищать старые записи регистра, которые более не актуальны (например, если из табличной части справочника удалили строку).
Рассмотрим правильный алгоритм работы с набором записей:
НаборЗаписей для нужного регистра.Записать().Посмотрим на программную реализацию в модуле объекта:
Процедура ПриЗаписи(Отказ)
// Создаем набор записей
Набор = РегистрыСведений.ТестовыйРегистр.СоздатьНаборЗаписей();
// Устанавливаем отбор, чтобы перезаписать данные только по текущему справочнику
Набор.Отбор.Наименование.Установить(Ссылка);
Для Каждого Стр Из РегистрРесурсы Цикл
НоваяЗапись = Набор.Добавить();
ЗаполнитьЗначенияСвойств(НоваяЗапись, Стр);
// Указываем измерение, по которому установлен отбор
НоваяЗапись.Наименование = Ссылка;
КонецЦикла;
// Записываем весь набор целиком (одна транзакция)
Набор.Записать();
КонецПроцедуры
Важное замечание: Обратите внимание, что мы перенесли код из обработчика ПередЗаписью в ПриЗаписи. Это критично для новых объектов. В ПередЗаписью у нового элемента справочника еще нет сформированной ссылки в базе данных (Ссылка может быть пустой), поэтому запись в регистр может завершиться ошибкой или создать некорректную связь.
Часто возникает вопрос: почему данные не переносятся, если в регистре поле имеет тип ссылки? Выясним причину. При использовании ЗаполнитьЗначенияСвойств система сопоставляет имена колонок и их типы. Если в табличной части колонка называется Товар и имеет тип СправочникСсылка.Номенклатура, а в регистре измерение называется также и имеет тот же тип, проблем не возникнет.
Если же вам нужно программно присвоить ссылку на другой объект, не присутствующий в строке напрямую, используйте обращение к метаданным или поиск:
// Пример получения ссылки из другого справочника
СсылкаНаСклад = Справочники.Склады.НайтиПоНаименованию("Основной склад");
НоваяЗапись.Склад = СсылкаНаСклад;
Помните, что присвоение Объект.Наименование (строкового значения) в поле, ожидающее Ссылку, приведет к тому, что поле в регистре останется пустым или возникнет ошибка приведения типов. Всегда проверяйте соответствие типов в конфигураторе.
Рассмотрим ситуации, с которыми часто сталкиваются разработчики:
МенеджерЗаписи без предварительного удаления старых данных, в регистре будут накапливаться "мусорные" строки. НаборЗаписей с отбором решает эту проблему автоматически.ЦенаТовара, а ресурс в регистре — Цена, метод ЗаполнитьЗначенияСвойств их "не увидит". В этом случае нужно прописывать назначение вручную: НоваяЗапись.Цена = Стр.ЦенаТовара;.Проанализируем работу с функцией ЗаполнитьЗначенияСвойств подробнее. Для вызова справки по ней всегда можно использовать комбинацию клавиш Ctrl+F1. Она сопоставляет свойства источника и приемника по именам. Если вы хотите исключить какие-то поля из копирования, вы можете указать их в третьем параметре функции в виде строки через запятую.
Мы проанализировали основные механизмы взаимодействия справочников и регистров. Использование Набора записей в событии ПриЗаписи является наиболее "чистым" и производительным решением. Это гарантирует, что данные в регистре всегда будут актуальны и синхронизированы с табличной частью вашего справочника, а система не будет перегружена лишними запросами к базе данных.