При разработке в среде 1С:Предприятие 8.3 на управляемых формах одной из самых частых задач является передача данных с клиента на сервер для обработки. Несмотря на кажущуюся простоту, начинающие разработчики часто сталкиваются с двумя типами ошибок: «Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа» и «Значение не является значением объектного типа (Добавить)». Разберем подробно, почему они возникают и как их правильно исправить.
Выясним причину возникновения ошибки передачи данных. Платформа 1С использует механизм сериализации для упаковки данных при пересылке между клиентским приложением и сервером. Не все объекты могут быть переданы напрямую. Разберем, какие типы данных разрешены, а какие — нет.
Разрешенные для передачи типы (сериализуемые):
Строка, Число, Булево, Дата.СправочникСсылка, ДокументСсылка).Массив, Структура, СписокЗначений, Соответствие.ФиксированныйМассив, ФиксированнаяСтруктура.Запрещенные типы:
ТаблицаЗначений и ДеревоЗначений (их нельзя передавать в параметрах серверных процедур).СправочникОбъект, ДокументОбъект).Если вы попытаетесь передать в параметре серверной процедуры ТаблицаЗначений, система выдаст ошибку «Значение недопустимого типа». Для передачи таких данных следует использовать временное хранилище.
Проанализируем ситуацию, когда код вызывает метод Добавить(), но получает ошибку. В 1С любая переменная, которая была объявлена, но не инициализирована, по умолчанию имеет тип Неопределено. У типа Неопределено нет свойств и методов, поэтому попытка обратиться к нему как к объекту приводит к краху программы.
Рассмотрим пример кода, который часто приводит к ошибке:
&НаКлиенте
Процедура КомандаВыполнить(Команда)
ПеременнаяМассив; // Здесь тип Неопределено
ОбработатьНаСервере(ПеременнаяМассив);
КонецПроцедуры
&НаСервере
Процедура ОбработатьНаСервере(МассивПараметр)
МассивПараметр.Добавить(1); // ОШИБКА: МассивПараметр = Неопределено
КонецПроцедуры
Рассмотрим верный способ передачи массива. Чтобы объект «ожил», его необходимо создать с помощью конструктора Новый. Посмотрим на рабочий пример:
&НаКлиенте
Процедура ВыполнитьПередачу()
// 1. Создаем объект на клиенте
МойМассив = Новый Массив;
МойМассив.Добавить("Элемент 1");
// 2. Передаем его в серверную процедуру
ОбработатьДанныеНаСервере(МойМассив);
// 3. После возврата с сервера массив будет содержать новые данные
Сообщить("Количество элементов: " + МойМассив.Количество());
КонецПроцедуры
&НаСервере
Процедура ОбработатьДанныеНаСервере(ПереданныйМассив)
// Массив передается по ссылке, изменения вернутся на клиент
ПереданныйМассив.Добавить("Элемент, добавленный на сервере");
КонецПроцедуры
Разберем типичную ошибку из обсуждения на форуме, когда функции по созданию массива существуют, но не вызываются. Проанализируем правильную структуру вызова функций:
&НаКлиенте
Функция СформироватьСписок()
Список = Новый СписокЗначений;
Список.Добавить("Проверка");
Возврат Список;
КонецФункции
&НаКлиенте
Процедура ОсновноеДействие()
// ОШИБКА: Просто написать ИмяФункции() недостаточно,
// результат нужно присвоить переменной
РезультатСписка = СформироватьСписок();
// Теперь передаем полученную переменную
ВыполнитьНаСервере(РезультатСписка);
КонецПроцедуры
&НаСервере
Процедура ВыполнитьНаСервере(СписокДляОбработки)
СписокДляОбработки.Добавить("Добавлено на сервере");
КонецПроцедуры
Если ваша задача — передать ТаблицаЗначений или другой несериализуемый тип, мы должны использовать Временное хранилище. Этот механизм позволяет поместить данные в специальную область памяти сервера и получить адрес в виде строки.
Разберем алгоритм работы с временным хранилищем:
ПоместитьВоВременноеХранилище().ПолучитьИзВременногоХранилища().Пример реализации:
&НаКлиенте
Процедура ПередатьТаблицуНаСервер()
// Допустим, у нас есть таблица значений на сервере, которую мы хотим обработать
АдресДанных = ПодготовитьДанныеНаСервере();
// Вызываем другую серверную процедуру, передавая адрес строки
ОбработатьДанныеПоАдресу(АдресДанных);
КонецПроцедуры
&НаСервере
Функция ПодготовитьДанныеНаСервере()
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Имя");
// Заполняем ТЗ...
// Помещаем во временное хранилище
Возврат ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификатор);
КонецФункции
&НаСервере
Процедура ОбработатьДанныеПоАдресу(Адрес)
// Извлекаем данные
Таблица = ПолучитьИзВременногоХранилища(Адрес);
// Работаем с таблицей...
КонецПроцедуры
Проанализируем еще несколько важных моментов, которые помогут избежать ошибок в будущем:
&НаСервере напрямую по имени.&НаСервереБезКонтекста, то сервер не знает о существовании реквизитов формы. В этом случае передача через параметры или временное хранилище является обязательной. Это работает быстрее, так как платформа не передает состояние всей формы.Процедура Имя(Знач Параметр), то любые изменения массива внутри этой процедуры останутся только на сервере и не вернутся на клиент. Будьте внимательны с этим модификатором.Таким образом, для успешной передачи данных всегда проверяйте: инициализирован ли объект (Новый), входит ли тип объекта в список разрешенных для сериализации и вызывается ли функция, возвращающая коллекцию, с присвоением результата переменной.