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

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

В процессе разработки на платформе 1С:Предприятие часто возникает задача автоматического создания или обновления записей в связанных справочниках. Типичный пример — создание записи в справочнике ФизическиеЛица на основании данных, введенных в форме справочника Контрагенты. Несмотря на кажущуюся простоту, начинающие программисты часто сталкиваются с ошибками установки системных реквизитов и непониманием того, почему данные «не переносятся».

В этой статье мы подробно разберем, как правильно реализовать механизм копирования данных, проанализируем ошибки при работе с методом ЗаполнитьЗначенияСвойств и выясним, как обеспечить корректную запись объекта в базу данных.

Разбор механизма ЗаполнитьЗначенияСвойств

Для начала проанализируем основной инструмент, который используется для копирования данных — метод ЗаполнитьЗначенияСвойств. Этот метод предназначен для копирования значений свойств из одного объекта (источника) в другой (приемник). Основное правило его работы: имена свойств в источнике и приемнике должны совпадать.

Синтаксис метода выглядит следующим образом:

ЗаполнитьЗначенияСвойств(Приемник, Источник, СписокСвойств, ИсключаяСвойства)

  1. Приемник — объект, в который мы записываем данные.
  2. Источник — объект или структура, откуда мы берем данные.
  3. СписокСвойств (необязательный) — строка с именами свойств, которые нужно заполнить (через запятую).
  4. ИсключаяСвойства (необязательный) — строка с именами свойств, которые следует пропустить.

Проблема 1: Ошибка установки значения свойства 'Родитель'

Рассмотрим ситуацию: вы пытаетесь скопировать данные из справочника Контрагенты в справочник ФизическиеЛица. Справочник Контрагенты может быть иерархическим (иметь группы), а ФизическиеЛица — нет. При вызове метода без параметров 1С пытается скопировать абсолютно все реквизиты, включая системные.

Если справочник-приемник не является многоуровневым, попытка установить свойство Родитель вызовет программную ошибку. Выясним причину: платформа видит у объекта-источника реквизит Родитель и пытается записать его в объект-приемник, у которого этого поля в метаданных просто не существует (или оно недоступно для записи в данном контексте).

Для решения этой проблемы необходимо использовать четвертый параметр метода — исключение. Рассмотрим правильный код:


НовСтрокаСпр = Справочники.ФизическиеЛица.СоздатьЭлемент();
// Указываем в четвертом параметре свойства, которые не нужно трогать
ЗаполнитьЗначенияСвойств(НовСтрокаСпр, ЭтотОбъект, , "Родитель, Владелец, Код");
НовСтрокаСпр.Записать();

Проблема 2: Ошибка установки значения свойства 'Владелец'

Аналогичная ситуация возникает со свойством Владелец. Если один справочник подчинен другому, а второй — нет, платформа выдаст ошибку при попытке прямого копирования. Даже если оба справочника плоские, системные механизмы 1С могут конфликтовать при попытке записи ссылки одного типа в поле владельца другого типа.

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

Почему поля остаются пустыми?

Часто после устранения ошибок выполнения кода разработчик замечает, что новый элемент создается, но его реквизиты (например, ФИО или Дата рождения) остаются пустыми. Выясним, почему так происходит.

Во-первых, проверьте соответствие имен. Если в Контрагентах поле называется ПолноеНаименование, а в ФизическихЛицах оно называется ФИО, метод ЗаполнитьЗначенияСвойств проигнорирует их. В этом случае данные нужно назначать вручную:


НовСтрокаСпр.ФИО = ЭтотОбъект.ПолноеНаименование;
НовСтрокаСпр.ИНН = ЭтотОбъект.ИНН;

Во-вторых, обратите внимание на типы данных. Если имена совпадают, но в одном справочнике это "Строка", а в другом "СправочникСсылка", автоматического приведения типов не произойдет, и значение не будет заполнено.

Использование флага ОбменДанными.Загрузка

В некоторых примерах кода встречается строка НовСтрокаСпр.ОбменДанными.Загрузка = Истина;. Разберем, для чего это нужно. Установка этого флага позволяет записать объект в базу данных "как есть", минуя большинство проверок, прописанных в модуле объекта в процедурах ПередЗаписью и ПриЗаписи.

Важно: использование этого метода является "костылем" в обычной разработке. Если вы создаете новое физическое лицо, должны сработать все проверки на дубли, проверка корректности ИНН и прочее. Устанавливая Загрузка = Истина, вы рискуете создать некорректные данные. Используйте это только в исключительных случаях, когда вы точно понимаете, что делаете.

Работа с формами: Ссылка vs Объект

Рассмотрим важный теоретический момент, который упоминался в обсуждении. В 1С существует разделение на Ссылку (указатель на данные в базе, только для чтения) и Объект (копия данных в памяти, доступная для изменения и записи).

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

  1. Создать новый объект через Справочники.ИмяСправочника.СоздатьЭлемент().
  2. Заполнить его реквизиты (автоматически или вручную).
  3. Вызвать метод Записать().

Если на вашей форме размещены реквизиты с типом СправочникОбъект, помните, что на управляемых формах данные хранятся в типе ДанныеФормыСтруктура. Чтобы получить из них полноценный объект для записи, нужно использовать преобразование РеквизитФормыВЗначение.

Итоговый рекомендуемый алгоритм

Посмотрим на пример правильной реализации сохранения данных в другой справочник при записи основного контрагента:


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

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

Разберем, что мы сделали в этом коде. Мы добавили проверку на дубликаты (по ИНН), использовали безопасную попытку записи, исключили системные поля, которые вызывают ошибки, и вручную заполнили те поля, имена которых не совпадают. Такой подход гарантирует стабильную работу программы и целостность базы данных.

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

← На главную