В процессе разработки в среде «1С:Предприятие» перед программистом часто возникает задача переноса данных из табличной части одного документа в табличную часть другого. Например, когда необходимо заполнить документ ПеремещениеТоваров на основании данных из ОтчетОРозничныхПродажах. При попытке сделать это «в лоб» начинающие разработчики часто сталкиваются с системными ошибками. Рассмотрим подробнее, почему возникают такие проблемы и как их правильно решать с точки зрения стандартов разработки «1С».
Проанализируем ситуацию, с которой столкнулся автор темы. Исходный код выглядел следующим образом:
СсылкаНаОтчет = ОтчетОРозничныхПродажах.Ссылка;
ДокПеремещение = Документы.ПеремещениеТоваров.СоздатьДокумент();
ДокПеремещение.Товары.Загрузить(СсылкаНаОтчет.Товары);
При выполнении этого кода система выдает ошибку «Неверные параметры». Давайте разберемся, почему так происходит.
Метод Загрузить(), применяемый к табличной части создаваемого документа (в нашем случае это ДокПеремещение.Товары), в качестве входного параметра строго ожидает объект типа ТаблицаЗначений.
Когда мы обращаемся к табличной части через ссылку на существующий в базе документ (СсылкаНаОтчет.Товары), платформа «1С» возвращает объект типа ТабличнаяЧастьСсылка. Платформа не может автоматически преобразовать ссылку на табличную часть в полноценную таблицу значений «на лету» внутри метода Загрузить(), что и приводит к падению программы с ошибкой несовместимости типов.
Для того чтобы исправить ошибку, нам необходимо предварительно получить данные табличной части в виде ТаблицыЗначений. Для этого у объекта табличной части существует метод Выгрузить(). Изменим наш исходный код:
СсылкаНаОтчет = ОтчетОРозничныхПродажах.Ссылка;
ДокПеремещение = Документы.ПеремещениеТоваров.СоздатьДокумент();
// Выгружаем табличную часть документа-источника в Таблицу Значений
ТаблицаТоваров = СсылкаНаОтчет.Товары.Выгрузить();
// Загружаем полученную таблицу значений в новый документ
ДокПеремещение.Товары.Загрузить(ТаблицаТоваров);
Этот способ прост в реализации и отлично работает в тех случаях, когда структура колонок в документе-источнике и документе-приемнике полностью совпадает. Метод Загрузить() автоматически сопоставит колонки с одинаковыми именами и перенесет данные.
Хотя метод Выгрузить() решает проблему быстро, в реальной разработке использовать его для получения данных из базы не рекомендуется. И вот почему:
СсылкаНаОтчет.Товары), мы заставляем платформу неявно считывать из базы данных весь документ-источник целиком (включая все реквизиты шапки и другие табличные части, если они есть), чтобы поместить этот массив в оперативную память.ОтчетОРозничныхПродажах и ПеремещениеТоваров имеют разное назначение. В отчете о продажах присутствуют специфические колонки (например, «Цена», «Сумма», «СтавкаНДС»), которые совершенно не нужны в документе перемещения. Загружая ТЧ напрямую, мы тащим в память лишние данные.Загрузить() не сможет перенести эти данные автоматически.Для оптимизации процесса разберем по шагам, как решить эту задачу с помощью запроса. Запрос обращается напрямую к таблицам СУБД, выбирая только строго необходимые поля и мгновенно формируя готовую структуру.
// 1. Создаем запрос для получения только нужных данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОтчетТовары.Номенклатура КАК Номенклатура,
| ОтчетТовары.Количество КАК Количество,
| ОтчетТовары.Характеристика КАК Характеристика
|ИЗ
| Документ.ОтчетОРозничныхПродажах.Товары КАК ОтчетТовары
|ГДЕ
| ОтчетТовары.Ссылка = &СсылкаНаОтчет";
Запрос.УстановитьПараметр("СсылкаНаОтчет", СсылкаНаОтчет);
// 2. Выгружаем результат запроса в Таблицу Значений
ТаблицаДляЗагрузки = Запрос.Выполнить().Выгрузить();
// 3. Создаем документ и загружаем очищенные данные
ДокПеремещение = Документы.ПеремещениеТоваров.СоздатьДокумент();
ДокПеремещение.Товары.Загрузить(ТаблицаДляЗагрузки);
Используя этот подход, мы гарантируем высокую скорость работы системы даже при обработке документов с тысячами строк.
Иногда пользователям требуется вручную копировать строки из одного открытого документа в другой. В сообщении форума предложен интересный способ реализации простейшего буфера обмена для Обычных форм (ОФ) с использованием платформенных методов СохранитьЗначение() и ВосстановитьЗначение().
Этот механизм можно оформить в виде двух внешних обработок заполнения табличных частей:
1. Обработка «ВБуфер» (копирование данных):
Процедура Инициализировать(Объект, ИмяТабличнойЧасти, ТабличноеПолеОбъекта) Экспорт
// Получаем ТЧ текущего документа
тч = Объект[ИмяТабличнойЧасти];
// Сохраняем выгруженную Таблицу Значений в системный буфер настроек пользователя
СохранитьЗначение("БуферТаблиц_ИмениКозлова", тч.Выгрузить());
Сообщить("Данные успешно скопированы в буфер!");
КонецПроцедуры
2. Обработка «ИзБуфера» (вставка данных):
Процедура Инициализировать(Объект, ИмяТабличнойЧасти, ТабличноеПолеОбъекта) Экспорт
// Восстанавливаем сохраненную Таблицу Значений из буфера
табл = ВосстановитьЗначение("БуферТаблиц_ИмениКозлова");
Если ТипЗнч(табл) = Тип("ТаблицаЗначений") И табл.Количество() > 0 Тогда
тч = Объект[ИмяТабличнойЧасти];
// Построчно переносим данные с сопоставлением свойств
Для каждого стр Из табл Цикл
нов = тч.Добавить();
ЗаполнитьЗначенияСвойств(нов, стр);
КонецЦикла;
Сообщить("Данные успешно вставлены из буфера!");
Иначе
Предупреждение("Буфер обмена пуст или содержит некорректные данные!");
КонецЕсли;
КонецПроцедуры
Использование метода ЗаполнитьЗначенияСвойств() в цикле добавления строк — это очень важный прием. Он позволяет скопировать только те реквизиты, которые совпадают по типу и имени в исходном документе и документе-приемнике, предотвращая любые ошибки несовместимости структуры табличных частей.
Стоит отметить, что методы СохранитьЗначение() и ВосстановитьЗначение() являются устаревшими и не поддерживаются на тонком клиенте в управляемом приложении. Если вы работаете в современных конфигурациях (таких как ERP, КА, УТ 11, Бухгалтерия 3.0), для обмена данными между формами следует использовать другие механизмы:
ПоместитьВоВременноеХранилище(), а полученный адрес (строка) передается в форму приемника, где извлекается с помощью ПолучитьИзВременногоХранилища().ХранилищеСистемныхНастроек.Сохранить() и ХранилищеСистемныхНастроек.Загрузить().Таким образом, мы разобрали все аспекты работы с табличными частями: от исправления простейших ошибок приведения типов до проектирования оптимальных алгоритмов работы с СУБД и создания пользовательских интерактивных инструментов.