При разработке на управляемых формах 1С программисты часто сталкиваются с задачей: пользователь выбирает строку в списке (например, загруженный заказ из интернет-магазина), и по нажатию кнопки система должна создать на основании этих данных реальный документ в базе. Однако попытка передать объект ТекущиеДанные напрямую в серверную процедуру приводит к ошибке рантайма. Разберем, почему это происходит и как правильно реализовать этот механизм.
Проанализируем ситуацию: в управляемом приложении программный код разделен на клиентскую и серверную части. Когда мы обращаемся к свойству Элементы.ИмяТаблицы.ТекущиеДанные, платформа возвращает объект типа ДанныеФормыСтруктура. Этот тип предназначен исключительно для отображения данных в интерфейсе и оптимизации работы тонкого клиента.
Важный нюанс: объекты типа ДанныеФормыСтруктура, ДанныеФормыКоллекция и им подобные не могут быть переданы с клиента на сервер в качестве параметров процедуры или функции. Платформа 1С строго ограничивает типы данных, которые могут пересекать границу "клиент-сервер" для обеспечения производительности и безопасности. Именно поэтому возникает ошибка "Недопустимое значение параметра".
Рассмотрим наиболее элегантный способ, который нашел автор темы. Вместо того чтобы пытаться передать "все данные сразу", мы передадим только уникальный ключ строки, а сами данные прочитаем уже на сервере непосредственно из реквизита формы.
Разберем по шагам, как это выглядит в коде:
&НаКлиенте
Процедура СохранитьЗаказ(Команда)
// Получаем доступ к текущей строке таблицы
Заказ = Элементы.ЗаказыНаИМ.ТекущиеДанные;
Если Заказ <> Неопределено Тогда
// Вместо передачи всего объекта, получаем его внутренний идентификатор
НомерСтроки = Заказ.ПолучитьИдентификатор();
// Вызываем серверную функцию, передавая только число (ID)
Если СохранитьЗаказНаСервере(НомерСтроки) Тогда
Сообщить("Заказ успешно создан!");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СохранитьЗаказНаСервере(ИдентификаторСтроки)
// На сервере у нас есть прямой доступ к реквизиту формы (Таблице Значений)
// Ищем строку по переданному ID
Заказ = ЗаказыИМ.НайтиПоИдентификатору(ИдентификаторСтроки);
Если Заказ <> Неопределено Тогда
Попытка
НовыйЗаказ = Документы.ЗаказКлиента.СоздатьДокумент();
НовыйЗаказ.Дата = ТекущаяДата();
НовыйЗаказ.Номер = Заказ.НомерЗаказа;
// Заполнение табличной части документа из вложенной коллекции
Для Каждого Позиция Из Заказ.ПозицииЗаказа Цикл
НоваяСтрока = НовыйЗаказ.Товары.Добавить();
НоваяСтрока.Номенклатура = Позиция.Товар;
НоваяСтрока.Количество = Позиция.Количество;
КонецЦикла;
НовыйЗаказ.Записать(РежимЗаписиДокумента.Запись);
Возврат Истина;
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
КонецЕсли;
Возврат Ложь;
КонецФункции
В данном примере ЗаказыИМ — это реквизит формы с типом ТаблицаЗначений. Метод НайтиПоИдентификатору позволяет мгновенно получить доступ к нужной строке на сервере, не передавая лишние данные по сети.
Иногда возникают ситуации, когда данные в таблице на форме являются временными и не связаны напрямую с реквизитами формы, или нам нужно передать данные, которые еще не записаны. В этом случае проанализируем подход с преобразованием данных в универсальные коллекции.
Структуры (Структура) и Массивы (Массив) — это типы данных, которые 1С умеет сериализовать и передавать между клиентом и сервером. Если у нас есть "ТЗ внутри ТЗ" (заказ и его товары), мы можем упаковать их следующим образом:
Посмотрим на пример реализации такого преобразования:
&НаКлиенте
Функция ПодготовитьДанныеДляСервера(ДанныеСтроки)
Результат = Новый Структура;
Результат.Вставить("Номер", ДанныеСтроки.Номер);
МассивТоваров = Новый Массив;
// Предположим, ПозицииЗаказа - это тоже коллекция данных формы
Для Каждого СтрТовар Из ДанныеСтроки.ПозицииЗаказа Цикл
ТекТовар = Новый Структура("Номенклатура, Количество, Цена", СтрТовар.Товар, СтрТовар.Количество, СтрТовар.Цена);
МассивТоваров.Добавить(ТекТовар);
КонецЦикла;
Результат.Вставить("Товары", МассивТоваров);
Возврат Результат;
КонецФункции
Такой объект "Структура" легко передается в любой серверный метод без ошибок.
Если данных очень много (например, XML содержит сотни заказов по тысячи строк в каждом), передача их через параметры может замедлить работу интерфейса. В таких случаях рекомендуется использовать ПоместитьВоВременноеХранилище.
Процесс выглядит так: на клиенте мы подготавливаем данные (или берем сам файл XML), помещаем его в хранилище и получаем Адрес (строку). На сервер передаем только этот адрес. Сервер извлекает данные методом ПолучитьИзВременногоХранилища, обрабатывает их и создает документы. Это минимизирует объем трафика между клиентским приложением и сервером приложений.
При программном создании документов из внешних источников (XML, JSON, API интернет-магазина) следует придерживаться нескольких правил, чтобы система работала стабильно:
Попытка...Исключение. При загрузке большого количества заказов используйте явные транзакции НачатьТранзакцию() и ЗафиксироватьТранзакцию().Объект.ДополнительныеСвойства.Вставить("Загрузка", Истина). Это часто позволяет обойти тяжелые проверки в модуле объекта при записи.Подводя итог, отметим, что ключ к успеху в управляемом приложении — четкое понимание того, какие типы данных являются "транспортабельными". Использование ПолучитьИдентификатор() — самый быстрый способ для интерактивной работы, а связка Массив + Структура — самый гибкий способ для передачи произвольных данных.