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