Как работать с ключами записей регистра сведений в управляемых формах 1С?

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

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

Почему возникает ошибка при передаче ключа записи на клиент

Проанализируем системные ограничения платформы 1С:Предприятие:

  1. Тип данных КлючЗаписи не является ссылочным типом (Ссылка). Он не поддерживается реквизитами метаданных (табличными частями обработок или документов) и не может быть добавлен в качестве явного типа колонки таблицы значений на уровне конфигуратора.
  2. Ограничения контекста тонкого клиента. Объект типа КлючЗаписи существует только на стороне сервера. Если поместить его в колонку с типом Произвольный, платформа попытается сериализовать данные формы при передаче контекста на клиент. Так как данный объект не сериализуется в контексте управляемой формы, возникает ошибка несоответствия типов.
  3. Особенность работы метода РеквизитФормыВЗначение. При каждом выполнении вызова РеквизитФормыВЗначение("Объект") платформа создает совершенно новый экземпляр прикладного объекта в оперативной памяти сервера. В него переносятся исключительно те реквизиты и табличные части, которые явно присутствуют в реквизитах формы. Любые экспортные переменные модуля объекта, внутренние таблицы и динамически созданные свойства не сохраняются между серверными вызовами и инициализируются заново значениями по умолчанию.

Вариант 1. Использование структуры ключевых полей (рекомендуемый способ)

Рассмотрим самое простое и универсальное решение: вместо передачи несериализуемого серверного объекта КлючЗаписи передавать на клиент обычную Структуру или сохранять ключевые поля непосредственно в колонках таблицы формы.

Для однозначной идентификации записи регистра сведений достаточно знать все его ключевые поля:

  1. Для непериодических независимых регистров — все измерения.
  2. Для периодических регистров — все измерения плюс поле Период.
  3. Для регистров с подчинением регистратору — поле Регистратор (и НомерСтроки при необходимости).

Посмотрим на пример формирования структуры ключевых полей на сервере и открытия формы записи:


&НаСервере
Функция ПолучитьПараметрыЗаписи(ИмяРегистра, СтруктураКлюча)
    // Формируем структуру параметров для открытия формы записи
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Ключ", СтруктураКлюча);
    Возврат ПараметрыФормы;
КонецФункции

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

Обратите внимание: для интерактивного открытия стандартной формы записи регистров через ОткрытьФорму нет необходимости создавать объектный КлючЗаписи. Платформа штатно принимает обычную Структуру в параметре Ключ, если имена ключей структуры в точности совпадают с именами измерений и реквизитов периодичности регистра.

Если же на сервере требуется именно объектный ключ (например, для вызова метода менеджера регистра), его можно легко воссоздать с помощью фабрики ключей:


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

Вариант 2. Преобразование таблицы значений в массив структур

Если на форме не требуется использовать стандартную таблицу формы, связанную с реквизитом, а данные нужны только для программной обработки и итерации на клиенте, таблицу значений можно конвертировать в массив структур:


&НаСервереБезКонтекста
Функция РазложитьТЗВМассив(ТаблицаДанных)
    МассивРезультат = Новый Массив;
    
    Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
        СтрокаСтруктура = Новый Структура;
        Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
            СтрокаСтруктура.Вставить(Колонка.Имя, СтрокаТЗ[Колонка.Имя]);
        КонецЦикла;
        МассивРезультат.Добавить(СтрокаСтруктура);
    КонецЦикла;
    
    Возврат МассивРезультат;
КонецФункции

Такой массив структур без проблем передается на сторону клиента и обходится стандартным циклом Для Каждого Элемент Из МассивРезультат Цикл.

Вариант 3. Явная типизация колонок таблицы формы

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

Преимущества такого подхода:

  1. Отсутствие проблем с сериализацией: данные формы типизированы и корректно передаются между клиентом и сервером.
  2. Штатный интерфейс: пользователь получает стандартные механизмы сортировки, поиска и автоподбора в полях ввода.
  3. Простота обратного чтения: при выполнении серверной процедуры достаточно прочитать строки таблицы формы и программно сформировать движения или менеджеры записей.

Вариант 4. Сохранение сложных серверных структур во временном хранилище

Если таблица значений содержит специфические типы данных или слишком большой объем информации, который не требуется отображать пользователю целиком, данные можно поместить во временное хранилище, передавая на клиент только адрес:


&НаСервере
Процедура ЗаполнитьИСохранитьДанные()
    // Заполняем тяжелую серверную таблицу значений
    ТаблицаДанных = ПолучитьТаблицуСлужебныхДанных();
    
    // Сохраняем во временное хранилище формы
    АдресХранилища = ПоместитьВоВременноеХранилище(ТаблицаДанных, УникальныйИдентификатор);
КонецПроцедуры

&НаСервере
Процедура ИзвлечьИОбработатьДанные()
    // Восстанавливаем данные на сервере при необходимости
    ТаблицаДанных = ПолучитьИзВременногоХранилища(АдресХранилища);
    Если ТаблицаДанных <> Неопределено Тогда
        // Выполняем обработку
    КонецЕсли;
КонецПроцедуры

Таким образом, для безопасной и корректной работы с записями регистров на управляемых формах следует отказаться от передачи объектов КлючЗаписи на сторону клиента, заменив их структурами ключевых полей либо явно типизированными колонками реквизитов формы.

← На главную