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

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

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

Разбор основной проблемы: Ссылка против Объекта

Разберем ситуацию, описанную автором темы. Основная ошибка заключалась в попытке манипулировать данными документа, обращаясь непосредственно к реквизиту СсылкаНаДокумент. В системе 1С:Предприятие крайне важно различать два понятия: Ссылка (DocumentRef) и Объект (DocumentObject).

Ссылка — это лишь «указатель» на запись в базе данных. Она предназначена для чтения и отображения в формах, но через нее невозможно изменить данные или структуру табличных частей. Объект — это копия данных из базы в оперативной памяти, которая позволяет вносить изменения, добавлять строки в ТЧ и выполнять метод Записать().

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

Пошаговый алгоритм реализации переноса данных

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

Шаг 1. Проверка заполнения реквизита.

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

Шаг 2. Получение объекта для редактирования.

Для модификации существующего документа необходимо вызвать метод ПолучитьОбъект(). Именно этот метод переводит данные из состояния «только чтение» в состояние редактирования.

Шаг 3. Перенос строк.

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

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


&НаСервере
Процедура ПеренестиДанныеВДокументНаСервере()
    
    // 1. Проверяем, выбран ли документ-приемник
    Если Не ЗначениеЗаполнено(Объект.СсылкаНаДокумент) Тогда
        Сообщить("Не выбран документ для загрузки данных!");
        Возврат;
    КонецЕсли;

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

Оптимизация: Метод Загрузить() вместо цикла

Если структура колонок табличной части обработки полностью совпадает со структурой ТЧ документа, мы можем значительно ускорить работу, избегая медленных циклов. Для этого используем выгрузку в ТаблицуЗначений.

Разберем, как это работает:

  1. Метод Выгрузить() создает копию данных ТЧ в виде таблицы значений.
  2. Мы можем передать массив найденных строк в этот метод, чтобы выгрузить только помеченные записи.
  3. Метод Загрузить() одним махом вставляет все строки в документ-приемник.

Пример оптимизированного подхода:


// Выгружаем помеченные строки в таблицу значений
ТаблицаСДанными = Объект.ТаблицаДокументов.Выгрузить(МассивСтрок);

// Загружаем всю таблицу целиком в объект документа
ДокОбъект.СписокДокументов.Загрузить(ТаблицаСДанными);

Важные нюансы при работе с контекстом и формами

При работе в управляемом приложении (1С v8.3) важно помнить о контексте выполнения. Манипуляции с объектами базы данных (такими как DocumentObject) возможны только &НаСервере. Попытка вызвать метод ПолучитьОбъект() в клиентской процедуре приведет к ошибке компиляции.

Также стоит обратить внимание на использование обращения ЭтотОбъект. В модуле управляемой формы ЭтотОбъект ссылается на саму форму (УправляемаяФорма), а данные, с которыми работает форма, хранятся в реквизите Объект. Поэтому правильно обращаться к табличной части обработки как Объект.ТаблицаДокументов, а не через ЭтотОбъект.Объект, что избыточно и может запутать при чтении кода.

Еще один критический момент — обновление открытых форм. Если в момент выполнения вашей обработки документ, в который вы записываете данные, открыт у другого пользователя (или у вас в другом окне), изменения в базе произойдут, но в открытой форме они не отобразятся. Чтобы система «узнала» об изменениях, можно использовать механизм оповещений:


// После записи на сервере, на клиенте можно вызвать:
ОповеститьОбИзменении(Объект.СсылкаНаДокумент);

Типичные ошибки и способы их решения

Проанализируем ситуации, когда код может не сработать:

  1. Ошибка «Объект заблокирован»: Возникает, если документ открыт другим пользователем или фоновым заданием. Рекомендуется всегда оборачивать метод Записать() в конструкцию Попытка...Исключение.
  2. Пустые значения в колонках: Проверьте соответствие имен колонок. ЗаполнитьЗначенияСвойств() работает по принципу совпадения имен. Если в обработке колонка называется Контрагент_JSON, а в документе Контрагент, данные не скопируются автоматически. В таком случае нужно явное присвоение: НоваяСтрока.Контрагент = СтрокаИст.Контрагент_JSON;.
  3. Очистка данных: Будьте осторожны с методом Очистить(). Если ваша задача — дополнить документ новыми строками, не вызывайте этот метод, иначе все созданные ранее записи в документе будут удалены.

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

← На главную