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

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

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

Базовая реализация через обход коллекции

Рассмотрим простейшую ситуацию: у нас есть две табличные части. В первой ТЧ (пусть это будет Товары) есть колонка СерийныйНомер, а во второй (например, ДополнительныеДанные) — колонка СерийныйНомер2. Нам нужно по нажатию кнопки «склеить» или перенести эти значения. Проанализируем самый лаконичный вариант решения задачи с помощью цикла по индексу:


Для инд = 0 по Объект.ДополнительныеДанные.Количество() - 1 Цикл
    Объект.Товары[инд].СерийныйНомер = "" + Объект.Товары[инд].СерийныйНомер + Объект.ДополнительныеДанные[инд].СерийныйНомер2;
КонецЦикла;

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

Обработка разницы в количестве строк (Безопасность)

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


КолвоСтрок1 = Объект.Товары.Количество();
КолвоСтрок2 = Объект.ДополнительныеДанные.Количество();
Предел = Мин(КолвоСтрок1, КолвоСтрок2);

Для инд = 0 по Предел - 1 Цикл
    ТекущаяСтрока = Объект.Товары[инд];
    Источник = Объект.ДополнительныеДанные[инд];
    ТекущаяСтрока.СерийныйНомер = ТекущаяСтрока.СерийныйНомер + Источник.СерийныйНомер2;
КонецЦикла;

Этот подход значительно надежнее, так как он исключает обращение к несуществующим строкам. Однако помните: если логика подразумевает добавление новых строк в первую ТЧ при их избытке во второй, то перед циклом следует программно вызвать метод Добавить() для первой коллекции.

Форматирование данных и использование разделителей

Простое склеивание строк (конкатенация) часто приводит к нечитаемости данных. Например, если в первой колонке было «SN100», а во второй «SN200», результат «SN100SN200» будет бесполезен для пользователя. Разберем, как добавить разделитель (например, запятую) только в тех случаях, когда это необходимо:


Для инд = 0 по Предел - 1 Цикл
    СтрокаПриемник = Объект.Товары[инд];
    ЗначениеИсточника = СокрЛП(Объект.ДополнительныеДанные[инд].СерийныйНомер2);
    
    Если ЗначениеЗаполнено(СтрокаПриемник.СерийныйНомер) Тогда
        СтрокаПриемник.СерийныйНомер = СтрокаПриемник.СерийныйНомер + ", " + ЗначениеИсточника;
    Иначе
        СтрокаПриемник.СерийныйНомер = ЗначениеИсточника;
    КонецЕсли;
КонецЦикла;

Такой код делает данные наглядными и структурированными. Использование функции СокрЛП() позволяет избавиться от лишних пробелов по краям значений.

Оптимизация: Клиент-серверное взаимодействие

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

  1. Создаем команду на форме и привязываем её к кнопке.
  2. В клиентской процедуре вызываем серверный метод.
  3. На сервере работаем напрямую с данными объекта.

&НаКлиенте
Процедура ПеренестиДанные(Команда)
    ПеренестиДанныеНаСервере();
КонецПроцедуры

&НаСервере
Процедура ПеренестиДанныеНаСервере()
    // Здесь выполняем перебор строк
    // После выполнения управление вернется на клиент, 
    // и форма автоматически отобразит изменения
КонецПроцедуры

Связь строк по ключевым полям

Работа по индексу (0, 1, 2...) допустима только тогда, когда вы абсолютно уверены, что порядок строк в обеих таблицах идентичен и никогда не меняется. Но что если пользователь отсортировал одну из таблиц по алфавиту? Данные перемешаются, и серийный номер попадет не к тому товару. Чтобы избежать этой серьезной проблемы, проанализируем использование ключей связи.

В профессиональных конфигурациях рекомендуется использовать скрытую колонку КлючСвязи (тип Число или УникальныйИдентификатор). В этом случае поиск строки-приемника будет выглядеть так:


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

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

Типы данных: Ссылки против Строк

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

Пример для работы со ссылочными типами:


// Если нужно получить текст из ссылки для записи в строковую колонку
СтрокаПриемник.СерийныйНомер = Строка(СтрокаИсточник.СерийныйНомер2);

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

Обновление интерфейса после переноса

Иногда после программного изменения данных пользователь не видит результата мгновенно. Хотя при работе с Объект на управляемой форме изменения обычно подтягиваются автоматически, в сложных случаях можно принудительно обновить элементы. Посмотрим, как это сделать:

Используйте метод ОповеститьОбИзменении(), если данные меняются в базе данных напрямую, или просто убедитесь, что ваши действия происходят в контексте &НаСервере текущей формы. Платформа сама отследит модифицированность данных и перерисует нужные ячейки табличных частей.

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

← На главную