Как передать строку таблицы (ДанныеФормыЭлементКоллекции) на сервер или программно получить список всех колонок?

Программист IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью передать данные конкретной строки таблицы (тип ДанныеФормыЭлементКоллекции) с клиента на сервер. Основная сложность заключается в том, что этот тип данных тесно связан с контекстом формы и не может быть передан напрямую во внеконтекстные серверные методы (&НаСервереБезКонтекста). Кроме того, ручное перечисление всех колонок в структуре при большом их количестве становится трудоемкой задачей. Рассмотрим подробно, как автоматизировать этот процесс и какие методы являются наиболее эффективными.

Метод 1: Использование идентификатора строки (Best Practice)

Проанализируем самый производительный и правильный с точки зрения архитектуры 1С способ. Вместо того чтобы передавать на сервер тяжелый объект или вручную созданную структуру, мы передаем только уникальный идентификатор строки. Этот метод идеально подходит для контекстных вызовов (&НаСервере).

Рассмотрим по шагам, как это реализовать:

  1. На клиенте мы получаем идентификатор текущей строки через метод ПолучитьИдентификатор().
  2. Передаем этот числовой идентификатор в серверную процедуру.
  3. На сервере восстанавливаем данные строки из реквизита формы, используя метод НайтиПоИдентификатору().

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


&НаКлиенте
Процедура ТаблицаПриИзменении(Элемент)
    
    ДанныеСтроки = Элементы.Таблица.ТекущиеДанные;
    Если ДанныеСтроки = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ИдентификаторСтроки = ДанныеСтроки.ПолучитьИдентификатор();
    ОбработатьСтрокуНаСервере(ИдентификаторСтроки);
    
КонецПроцедуры

&НаСервере
Процедура ОбработатьСтрокуНаСервере(ИдентификаторСтроки)
    
    // Восстанавливаем строку из реквизита формы (например, Объект.Товары)
    СтрокаКоллекции = Объект.Товары.НайтиПоИдентификатору(ИдентификаторСтроки);
    
    Если СтрокаКоллекции <> Неопределено Тогда
        // Теперь у нас есть доступ ко всем полям строки
        СтрокаКоллекции.Цена = 100; 
        // Сумма пересчитается, так как мы работаем в контексте формы
    КонецЕсли;
    
КонецПроцедуры

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

Метод 2: Автоматическое создание структуры через ПолучитьРеквизиты

Если же вам необходимо вызвать внеконтекстный метод (&НаСервереБезКонтекста), передать идентификатор не получится, так как вне контекста сервер не "видит" реквизиты формы. В этом случае данные нужно упаковать в Структура. Чтобы не прописывать имена всех колонок вручную, воспользуемся программным обходом реквизитов.

Разберем ситуацию: нам нужно считать все имена колонок программно. Для этого используется метод формы ПолучитьРеквизиты(). Выясним причину, почему это лучше делать один раз: получение состава реквизитов — операция относительно тяжелая, поэтому список имен колонок стоит кэшировать или получать при создании формы.

Пример функции для динамического создания структуры из строки таблицы:


&НаКлиенте
Функция ПолучитьСтруктуруИзСтроки(ТаблицаИмя, ТекущиеДанные)
    
    Результат = Новый Структура;
    
    // Получаем список имен колонок (имена реквизитов этой таблицы на форме)
    СписокКолонок = ПолучитьИменаКолонокСервер(ТаблицаИмя);
    
    Для Каждого ИмяКолонки Из СписокКолонок Цикл
        Результат.Вставить(ИмяКолонки, ТекущиеДанные[ИмяКолонки]);
    КонецЦикла;
    
    Возврат Результат;
    
КонецФункции

&НаСервере
Функция ПолучитьИменаКолонокСервер(ПутьКДаннымТаблицы)
    
    МассивИмен = Новый Массив;
    
    // Получаем массив объектов РеквизитФормы, принадлежащих таблице
    РеквизитыТаблицы = ЭтаФорма.ПолучитьРеквизиты(ПутьКДаннымТаблицы);
    
    Для Каждого Реквизит Из РеквизитыТаблицы Цикл
        МассивИмен.Добавить(Реквизит.Имя);
    КонецЦикла;
    
    Возврат МассивИмен;
    
КонецФункции

В этом примере мы используем ПутьКДанным (например, "Объект.Товары"), чтобы сервер точно определил, какие колонки принадлежат коллекции. Это позволяет избежать ошибок, если на форме есть элементы, не связанные с данными.

Метод 3: Использование ЗаполнитьЗначенияСвойств

Рассмотрим еще один практичный способ, который часто применяется в типовых конфигурациях. Если вы заранее знаете, какие поля вам нужны, или их список совпадает с полями какой-то структуры, используйте встроенную функцию ЗаполнитьЗначенияСвойств. Она умеет работать с ДанныеФормыЭлементКоллекции как с источником данных.


&НаКлиенте
Процедура ПередатьДанныеЧерезЗаполнение()
    
    ТекДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекДанные = Неопределено Тогда Возврат; КонецЕсли;
    
    // Создаем структуру с именами нужных полей
    ДанныеДляСервера = Новый Структура("Номенклатура, Количество, Цена, Сумма");
    
    // Магия платформы: свойства автоматически перенесутся из ДФЭК в структуру
    ЗаполнитьЗначенияСвойств(ДанныеДляСервера, ТекДанные);
    
    ВызватьСервернуюОбработку(ДанныеДляСервера);
    
КонецПроцедуры

Преимущество этого метода: Скорость разработки и читаемость кода. Вы явно указываете, какие данные уходят на сервер, используя принципы модели объекта, что упрощает отладку.

Метод 4: Работа в контекстных вызовах (автоматическая передача)

Многие разработчики забывают, что в рамках контекстного вызова (&НаСервере) объект ДанныеФормыЭлементКоллекции доступен для использования в качестве параметра процедур и функций. Платформа сама управляет передачей ссылки на этот объект.

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


&НаКлиенте
Процедура РасчитатьСкидку(Элемент)
    // Передаем весь объект строки целиком
    РасчитатьНаСервере(Элементы.Товары.ТекущиеДанные);
КонецПроцедуры

&НаСервере
Процедура РасчитатьНаСервере(СтрокаДанных)
    // СтрокаДанных здесь имеет тип ДанныеФормыЭлементКоллекции
    // Мы можем проверять наличие свойств через Свойство()
    Если СтрокаДанных.Количество > 10 Тогда
         СтрокаДанных.Скидка = 5;
    КонецЕсли;
КонецПроцедуры

Сравнение подходов и рекомендации

Выясним, какой метод выбрать в зависимости от задачи:

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

Важное предостережение: Помните, что данные в ТекущиеДанные на сервере могут не содержать изменений, которые пользователь только что внес в ячейку, если фокус еще не покинул поле ввода. Перед вызовом сервера рекомендуется использовать метод ПроверитьЗаполнение() или дождаться события ПриИзменении, которое гарантирует фиксацию данных в коллекции.

Таким образом, мы разобрали все основные способы взаимодействия с элементами коллекций форм. Выбор конкретного инструмента зависит от требований к контексту и необходимости универсальности кода. Использование НайтиПоИдентификатору остается самым надежным способом для 90% задач при разработке в управляемом приложении.

← На главную