Какие данные невозможно передать с клиента на сервер в 1С и почему?

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

При разработке на платформе 1С в клиент-серверном режиме часто возникает вопрос: почему при вызове серверной процедуры возникает ошибка "Значение недопустимого типа"? Какие данные можно передавать, а какие — нет, и в чем кроется причина этих ограничений? Давайте подробно разберемся в этом фундаментальном аспекте архитектуры 1С.

Основная причина ограничений — это процесс сериализации. Когда клиентский код вызывает процедуру с директивой &НаСервере, все передаваемые параметры должны быть преобразованы (сериализованы) в формат, пригодный для отправки по сети. На сервере происходит обратный процесс — десериализация. Соответственно, если тип данных не может быть корректно преобразован в текстовый или двоичный поток и затем восстановлен, его передача невозможна.

Ключевой принцип: Сериализация и мутабельность

Главный класс данных, которые нельзя передавать напрямую, — это мутабельные (изменяемые) значения. Мутабельный тип — это сложный объект, внутреннее состояние которого может меняться после его создания. Платформа 1С намеренно запрещает их передачу, чтобы избежать серьезных проблем с целостностью и рассинхронизацией данных.

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

Какие типы данных передать нельзя: конкретные примеры

Рассмотрим основные категории непередаваемых данных и разберем, почему с ними возникают проблемы.

  1. Прикладные объекты базы данных

    Это самый распространенный случай. Объекты вроде ДокументОбъект.<Имя>, СправочникОбъект.<Имя> или РегистрСведенийНаборЗаписей.<Имя> являются мутабельными. Они не просто хранят данные, но и тесно связаны с базой данных, имеют внутреннее состояние (модифицированность, признак нового объекта) и методы для взаимодействия с БД (Записать(), Прочитать()), которые могут быть выполнены только на сервере.

    Как правильно: Вместо самого объекта всегда передавайте его ссылку (например, СправочникСсылка.Номенклатура). Ссылка — это легковесный, сериализуемый идентификатор. Получив ссылку на сервере, вы можете получить полноценный объект из базы данных и работать с ним.

    
    // Неправильно! Такой код вызовет ошибку.
    &НаКлиенте
    Процедура СоздатьНаСервереНеправильно()
        НовыйЭлемент = ПолучитьФорму("Справочник.Контрагенты.Форма.ФормаЭлемента");
        ОбъектКонтрагента = НовыйЭлемент.Объект;
        ОбъектКонтрагента.Наименование = "Новый контрагент";
        
        // Ошибка: передача мутабельного значения (СправочникОбъект) невозможна.
        ЗаписатьОбъектНаСервере(ОбъектКонтрагента); 
    КонецПроцедуры
    
    // Правильно! Передаем данные в структуре.
    &НаКлиенте
    Процедура СоздатьНаСервереПравильно()
        ДанныеДляСоздания = Новый Структура;
        ДанныеДляСоздания.Вставить("Наименование", "Новый контрагент");
        ДанныеДляСоздания.Вставить("ИНН", "1234567890");
        
        СоздатьИЗаписатьОбъектНаСервере(ДанныеДляСоздания);
    КонецПроцедуры
    
    &НаСервере
    Процедура СоздатьИЗаписатьОбъектНаСервере(ДанныеДляСоздания)
        НовыйОбъект = Справочники.Контрагенты.СоздатьЭлемент();
        ЗаполнитьЗначенияСвойств(НовыйОбъект, ДанныеДляСоздания);
        НовыйОбъект.Записать();
    КонецПроцедуры
    
  2. Объекты, привязанные к контексту выполнения

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

    • COM-объекты. Классический пример. COMОбъект — это не данные, а скорее "пульт управления" внешней программой (например, Excel или Word), запущенной на клиентской машине. Передать его на сервер невозможно, так как на сервере нет этого экземпляра программы, и его внутреннее состояние не может быть воссоздано.
    • Дескрипторы файлов и устройств. Яркий пример из обсуждения на форуме — дескриптор COM-порта, к которому подключены торговые весы. Этот дескриптор — просто число, которое операционная система клиента связывает с физическим портом. Для серверной ОС это число не имеет никакого смысла, так как весы к серверу не подключены. Передавать нужно не дескриптор, а данные, полученные с устройства (например, вес товара).
    • Элементы управления и объекты формы. Нельзя передать на сервер кнопку, поле ввода или объект УправляемаяФорма целиком. Серверный код работает с данными формы (реквизитами), а не с их визуальным представлением. Платформа сама обеспечивает синхронизацию реквизитов формы при контекстных серверных вызовах.
  3. Специфические типы данных платформы

    Существуют и менее очевидные ограничения. Например, попытка передать строку, содержащую некоторые управляющие (непечатные) символы, может вызвать ошибку сериализации. Также не все служебные объекты платформы предназначены для передачи между клиентом и сервером.

Как правильно организовать передачу данных?

Хотя многие типы данных передать напрямую нельзя, существуют стандартные и эффективные способы работы в клиент-серверной архитектуре.

  1. Передача по ссылке. Как уже упоминалось, для объектов БД — это основной и единственно верный способ.
  2. Использование универсальных коллекций. Сложные клиентские объекты перед вызовом сервера следует "разобрать" на простые типы (число, строка, дата, булево) и упаковать в универсальные коллекции, которые отлично сериализуются: Структура, Соответствие, Массив, ТаблицаЗначений.
  3. Временное хранилище. Для передачи больших объемов данных (таблиц, двоичных данных файлов) этот механизм является самым эффективным. Данные помещаются в специальное хранилище на сервере, а клиенту возвращается уникальный адрес (строка). Этот адрес легковесный, и его можно свободно передавать с клиента на сервер и обратно.

    Посмотрим на пример:

    
    // На клиенте: помещаем большую таблицу в хранилище и передаем адрес на сервер
    &НаКлиенте
    Процедура ОбработатьБольшиеДанные()
        БольшаяТаблица = ПолучитьОченьБольшуюТаблицуЗначений();
        
        // Помещаем данные во временное хранилище и получаем адрес
        АдресХранилища = "";
        ПоместитьВоВременноеХранилище(БольшаяТаблица, АдресХранилища);
        
        // Вызываем серверную процедуру, передавая только легкую строку-адрес
        ОбработатьДанныеНаСервере(АдресХранилища);
    КонецПроцедуры
    
    // На сервере: получаем данные из хранилища по адресу и работаем с ними
    &НаСервере
    Процедура ОбработатьДанныеНаСервере(АдресХранилища)
        // Получаем данные из хранилища. После этого адрес становится недействительным
        ДанныеИзХранилища = ПолучитьИзВременногоХранилища(АдресХранилища);
        
        Если ДанныеИзХранилища <> Неопределено Тогда
            // Выполняем длительную обработку полученной таблицы
            Для Каждого Строка Из ДанныеИзХранилища Цикл
                // ...
            КонецЦикла;
        КонецЕсли;
    КонецПроцедуры
    

В заключение, главный принцип клиент-серверного взаимодействия в 1С — это четкое разделение данных и контекста их выполнения. На сервер всегда должны передаваться "чистые" данные (примитивные типы, ссылки, универсальные коллекции), а все объекты, связанные с базой данных или клиентским окружением, должны создаваться и использоваться исключительно на своей стороне: прикладные объекты — на сервере, COM-объекты — на клиенте. Такой подход гарантирует предсказуемость, надежность и производительность вашей системы.

← На главную