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