Какие универсальные коллекции нельзя передавать между клиентом и сервером?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Универсальные коллекции: ограничения при передаче между клиентом и сервером
Это классический вопрос на собеседованиях и в практике работы с архитектурой клиент-сервер в 1С. Рассмотрю все коллекции, которые передавать нельзя, почему и как обойти ограничения.
Краткий ответ
Нельзя передавать следующие коллекции:
- Соответствие (Map)
- Список (List) — только в некоторых случаях
- Дерево значений (Tree)
Можно передавать:
- Массив (Array) — всегда
- ТаблицаЗначений (Table) — всегда
- Структура (Structure) — всегда
Почему эти ограничения существуют
В архитектуре 1С клиент и сервер работают на разных машинах и используют сериализацию данных при передаче. Не все типы коллекций сериализуются одинаково.
Проблема 1: Соответствие (Map)
Нельзя передать от сервера к клиенту (и наоборот):
// ❌ ЭТО ВЫЗОВЕТ ОШИБКУ
Функция ПолучитьСоответствие() Экспорт
ДанныеСоответствия = Новое Соответствие;
ДанныеСоответствия.Вставить("Ключ1", "Значение1");
ДанныеСоответствия.Вставить("Ключ2", "Значение2");
Возврат ДанныеСоответствия; // Ошибка при передаче!
КонецФункции
Почему: Соответствие сохраняет порядок и использует хеширование, что не сериализуется.
Решение — преобразовать в Структуру:
// ✅ ПРАВИЛЬНО
Функция ПолучитьДанные() Экспорт
// Используем Структуру вместо Соответствия
ДанныеСтруктура = Новая Структура;
ДанныеСтруктура.Вставить("Ключ1", "Значение1");
ДанныеСтруктура.Вставить("Ключ2", "Значение2");
Возврат ДанныеСтруктура; // OK!
КонецФункции
Или преобразовать в Массив пар:
// ✅ АЛЬТЕРНАТИВА
Функция ПолучитьДанныеКакМассив() Экспорт
ДанныеСоответствия = Новое Соответствие;
ДанныеСоответствия.Вставить("Ключ1", "Значение1");
ДанныеСоответствия.Вставить("Ключ2", "Значение2");
// Преобразуем в массив структур [ключ, значение]
МассивДанных = Новый Массив;
Для Каждого Пара Из ДанныеСоответствия Цикл
НоваяПара = Новая Структура("Ключ,Значение", Пара.Ключ, Пара.Значение);
МассивДанных.Добавить(НоваяПара);
КонецЦикла;
Возврат МассивДанных; // OK!
КонецФункции
Проблема 2: Список (List)
Ограничено — можно передать только ПУСТОЙ Список:
// ❌ ОШИБКА — Список с данными
Функция ПолучитьСписок() Экспорт
МойСписок = Новый Список;
МойСписок.Добавить("Элемент1");
МойСписок.Добавить("Элемент2");
Возврат МойСписок; // Ошибка при передаче!
КонецФункции
// ✅ ОК — пустой Список
Функция ПолучитьПустойСписок() Экспорт
МойСписок = Новый Список; // Без элементов
Возврат МойСписок; // OK!
КонецФункции
Решение — использовать Массив:
// ✅ ПРАВИЛЬНО
Функция ПолучитьДанные() Экспорт
МойМассив = Новый Массив;
МойМассив.Добавить("Элемент1");
МойМассив.Добавить("Элемент2");
Возврат МойМассив; // OK!
КонецФункции
Проблема 3: Дерево значений (Tree)
Нельзя передать напрямую:
// ❌ ОШИБКА
Функция ПолучитьДерево() Экспорт
МойСтруктураДерева = Новое ДеревоЗначений;
МойСтруктураДерева.Колонки.Добавить("Номер");
МойСтруктураДерева.Колонки.Добавить("Наименование");
СтрокаДерева = МойСтруктураДерева.Строки.Добавить();
СтрокаДерева.Номер = "1";
Возврат МойСтруктураДерева; // Ошибка при передаче!
КонецФункции
Решение 1 — преобразовать в ТаблицуЗначений:
// ✅ ВАРИАНТ 1: Как плоская таблица
Функция ПолучитьДеревоКакТабличку() Экспорт
ТабДанных = Новая ТаблицаЗначений;
ТабДанных.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число"));
ТабДанных.Колонки.Добавить("Номер", Новый ОписаниеТипов("Строка"));
ТабДанных.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
ТабДанных.Колонки.Добавить("РодительНомер", Новый ОписаниеТипов("Строка"));
// Заполняем как иерархию
СтрокаРодитель = ТабДанных.Добавить();
СтрокаРодитель.Уровень = 0;
СтрокаРодитель.Номер = "1";
СтрокаРодитель.Наименование = "Родитель";
СтрокаДочка = ТабДанных.Добавить();
СтрокаДочка.Уровень = 1;
СтрокаДочка.Номер = "1.1";
СтрокаДочка.Наименование = "Дочка";
СтрокаДочка.РодительНомер = "1";
Возврат ТабДанных; // OK!
КонецФункции
Решение 2 — сериализация в JSON:
// ✅ ВАРИАНТ 2: Через JSON
Функция ПолучитьДеревоКакJSON() Экспорт
МойСтруктураДерева = Новое ДеревоЗначений;
МойСтруктураДерева.Колонки.Добавить("Номер");
МойСтруктураДерева.Колонки.Добавить("Наименование");
// Заполняем дерево
СтрокаДерева = МойСтруктураДерева.Строки.Добавить();
СтрокаДерева.Номер = "1";
СтрокаДерева.Наименование = "Корень";
// Сериализуем
JSONДерева = ДеревоВJSON(МойСтруктураДерева);
Возврат JSONДерева; // Возвращаем строку JSON
КонецФункции
Функция ДеревоВJSON(Дерево)
МассивДанных = ДеревоВМассив(Дерево.Строки);
Возврат ПреобразоватьВJSON(МассивДанных);
КонецФункции
Функция ДеревоВМассив(СтрокиДерева)
МассивСтрок = Новый Массив;
Для Каждого Строка Из СтрокиДерева Цикл
ДанныеСтроки = Новая Структура();
ДанныеСтроки.Вставить("Номер", Строка.Номер);
ДанныеСтроки.Вставить("Наименование", Строка.Наименование);
// Рекурсивно добавляем потомков
Если Строка.Строки.Количество() > 0 Тогда
ДанныеСтроки.Вставить("Потомки", ДеревоВМассив(Строка.Строки));
КонецЕсли;
МассивСтрок.Добавить(ДанныеСтроки);
КонецЦикла;
Возврат МассивСтрок;
КонецФункции
Таблица совместимости
| Тип коллекции | Можно передать | Примечания |
|---|---|---|
| Массив | ✅ Да | Всегда работает |
| Структура | ✅ Да | Всегда работает |
| ТаблицаЗначений | ✅ Да | Отличный выбор |
| Соответствие | ❌ Нет | Использовать Структуру |
| Список | ⚠️ Только пустой | Использовать Массив |
| ДеревоЗначений | ❌ Нет | Использовать ТаблицаЗначений + иерархия |
| ФиксированныеДанные | ✅ Да | Иммутабельная обёртка |
Практические примеры
Сценарий: нужно вернуть результаты поиска со сложной структурой
// ❌ НЕПРАВИЛЬНО
Функция ПолучитьРезультатыПоиска(ПоисковыйТекст) Экспорт
Результаты = Новое Соответствие; // ОШИБКА!
// ...
Возврат Результаты;
КонецФункции
// ✅ ПРАВИЛЬНО
Функция ПолучитьРезультатыПоиска(ПоисковыйТекст) Экспорт
ТабЛтатов = Новая ТаблицаЗначений;
ТабЛтатов.Колонки.Добавить("ID", Новый ОписаниеТипов("Строка"));
ТабЛтатов.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
ТабЛтатов.Колонки.Добавить("Рейтинг", Новый ОписаниеТипов("Число"));
// Заполняем результаты
Для Каждого Товар Из НайтиТовары(ПоисковыйТекст) Цикл
НоваяСтрока = ТабЛтатов.Добавить();
НоваяСтрока.ID = Товар.Ссылка.УникальныйИдентификатор();
НоваяСтрока.Наименование = Товар.Наименование;
НоваяСтрока.Рейтинг = Товар.Рейтинг;
КонецЦикла;
Возврат ТабЛтатов; // OK!
КонецФункции
Общие принципы
Правило 1: Передавай по сети только простые типы
- Массивы простых типов ✅
- Таблицы значений ✅
- Структуры с простыми полями ✅
- Всё остальное ❌
Правило 2: Для сложных структур используй ТаблицаЗначений
- Легко сериализуется
- Легко десериализуется
- Быстрая передача
- Понятная структура
Правило 3: Если нужна иерархия, добавь поле уровня/родителя
ТабДанных.Колонки.Добавить("Уровень");
ТабДанных.Колонки.Добавить("РодительИД");
Правило 4: Для очень сложных структур используй JSON
- Универсальный формат
- Поддерживается везде
- Легко отладить
В итоге, это важное ограничение архитектуры, которое разработчик должен помнить при работе с клиент-серверными приложениями в 1С. Знание этих нюансов спасает от многих ошибок в production.