Мы с вами часто сталкиваемся с необходимостью получить доступ к значениям реквизитов формы из серверного кода. Это может быть нужно для выполнения сложных расчетов, проверки данных перед записью или взаимодействия с другими объектами базы данных. Однако, архитектура 1С:Предприятия с разделением на клиент и сервер накладывает свои особенности на этот процесс. В этом материале мы подробно разберем, как получить реквизиты формы на сервере, рассмотрим различные подходы и выясним, какой из них оптимален в той или иной ситуации.
Самый простой и очевидный способ получить доступ к реквизитам формы на сервере — это использовать контекстный серверный вызов. Давайте проанализируем, как это работает.
Когда мы вызываем серверную процедуру или функцию из модуля формы (например, из клиентской процедуры кнопки) с директивой компиляции &НаСервере, платформа 1С:Предприятие автоматически упаковывает весь контекст формы. Это включает в себя не только ее реквизиты, но и элементы, параметры и другие данные. Упакованный контекст передается на сервер, где создается серверная часть формы, и контекст разворачивается. Только после этого выполняется код нашей серверной процедуры.
Благодаря этому механизму, внутри серверной процедуры мы можем обращаться к реквизитам формы напрямую через объект ЭтаФорма.
Важный момент: Необходимо различать реквизиты, принадлежащие непосредственно форме (добавленные в конфигураторе к форме), и реквизиты основного объекта данных формы (например, документа, справочника или другого объекта, который форма редактирует). Реквизиты основного объекта доступны через сам объект данных (например, Объект.ИмяРеквизита) как на клиенте, так и на сервере. Реквизиты формы же "живут" только тогда, когда форма открыта и ее контекст доступен.
Рассмотрим пример:
// В модуле формы
&НаСервере
Процедура МояСервернаяПроцедура()
// Здесь мы можем получить значение реквизита формы
// Например, если у формы есть реквизит "МойРеквизитФормы"
ЗначениеРеквизита = ЭтаФорма.МойРеквизитФормы;
// Использовать значение в серверной логике
СообщитьНаКлиенте("Значение реквизита формы на сервере: " + ЗначениеРеквизита);
// Если форма работает с объектом, например, документом
Если ЭтаФорма.Объект.Вид() = "Документ.МойДокумент" Тогда
// Мы также можем получить реквизиты объекта
ЗначениеРеквизитаОбъекта = ЭтаФорма.Объект.Номер;
СообщитьНаКлиенте("Номер объекта: " + ЗначениеРеквизитаОбъекта);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура КнопкаВыполнитьНаСервереНажатие(Команда)
// Вызываем серверную процедуру
МояСервернаяПроцедура();
КонецПроцедуры
Обратите внимание: Процесс упаковки и передачи всего контекста формы может быть достаточно ресурсоемким, особенно для сложных форм с большим количеством элементов и реквизитов. Это может замедлять работу приложения. Поэтому, если вам нужны лишь некоторые значения, стоит рассмотреть следующий подход.
Если для выполнения серверной задачи нам не требуется весь контекст формы, а нужны лишь значения нескольких конкретных реквизитов, мы можем значительно повысить производительность, используя внеконтекстные серверные вызовы с директивой компиляции &НаСервереБезКонтекста.
В этом случае, необходимые значения реквизитов формы следует явно передавать в качестве параметров серверной функции или процедуры. Это позволяет избежать передачи всей формы на сервер, что существенно экономит сетевой трафик и ресурсы сервера.
Разберем по шагам:
&НаСервереБезКонтекста, передавая полученные значения в качестве параметров.ЭтаФорма.Посмотрим на пример:
// В модуле формы
&НаСервереБезКонтекста
Функция МояСервернаяФункцияБезКонтекста(ЗначениеРеквизита1, ЗначениеРеквизита2)
// В этой функции у нас нет доступа к ЭтаФорма
// Мы работаем только с переданными параметрами
Результат = ЗначениеРеквизита1 + ЗначениеРеквизита2;
Возврат Результат;
КонецФункции
&НаКлиенте
Процедура КнопкаВыполнитьНаСервереБезКонтекстаНажатие(Команда)
// Получаем значения реквизитов формы на клиенте
Значение1 = ЭтаФорма.РеквизитФормы1;
Значение2 = ЭтаФорма.РеквизитФормы2;
// Вызываем серверную функцию, передавая значения как параметры
РезультатСервернойРаботы = МояСервернаяФункцияБезКонтекста(Значение1, Значение2);
Сообщить("Результат с сервера: " + РезультатСервернойРаботы);
КонецПроцедуры
Этот подход предпочтителен, когда вам нужны только данные, а не интерактивное взаимодействие с формой на сервере.
Иногда нам нужно не текущее значение реквизита открытой формы, а информация о самой структуре формы — какие реквизиты в ней есть, их типы, синонимы и так далее. Это информация о метаданных формы.
Мы можем получить эту информацию программно, используя свойство глобального контекста Метаданные.
Если мы находимся в модуле самой формы, мы можем получить коллекцию ее реквизитов через ЭтаФорма.Метаданные().Реквизиты. Это даст нам доступ к описанию реквизитов, но не к их текущим значениям.
&НаСервере
Процедура ВывестиМетаданныеРеквизитовТекущейФормы()
СообщитьНаКлиенте("Метаданные реквизитов текущей формы:");
Для Каждого РеквизитФормы Из ЭтаФорма.Метаданные().Реквизиты Цикл
СообщитьНаКлиенте(" Имя: " + РеквизитФормы.Имя + ", Тип: " + РеквизитФормы.Тип.Имя + ", Синоним: " + РеквизитФормы.Синоним);
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура КнопкаПоказатьМетаданныеНажатие(Команда)
ВывестиМетаданныеРеквизитовТекущейФормы();
КонецПроцедуры
Для получения информации о реквизитах *любой* формы (например, формы документа или справочника), не обязательно открытой, на этапе конфигурирования (дизайн-тайм), мы используем объект Метаданные глобального контекста.
&НаСервереБезКонтекста
Функция ПолучитьОписаниеРеквизитовФормыДокумента(ИмяДокумента, ИмяФормы)
КоллекцияОписанийРеквизитов = Новый Массив;
// Проверяем существование документа
Если Метаданные.Документы.Найти(ИмяДокумента) Тогда
ДокументМетаданные = Метаданные.Документы[ИмяДокумента];
// Проверяем существование формы для этого документа
Если ДокументМетаданные.Формы.Найти(ИмяФормы) Тогда
ФормаМетаданные = ДокументМетаданные.Формы[ИмяФормы];
// Перебираем реквизиты формы
Для Каждого Реквизит Из ФормаМетаданные.Реквизиты Цикл
КоллекцияОписанийРеквизитов.Добавить("Имя: " + Реквизит.Имя + ", Тип: " + Реквизит.Тип.Имя + ", Синоним: " + Реквизит.Синоним);
КонецЦикла;
КонецЕсли;
КонецЕсли;
Возврат КоллекцияОписанийРеквизитов;
КонецФункции
&НаКлиенте
Процедура КнопкаПолучитьМетаданныеПроизвольнойФормыНажатие(Команда)
ОписаниеРеквизитов = ПолучитьОписаниеРеквизитовФормыДокумента("РеализацияТоваровУслуг", "ФормаДокумента");
Если ОписаниеРеквизитов.Количество() > 0 Тогда
Сообщить("Реквизиты формы документа 'РеализацияТоваровУслуг.ФормаДокумента':");
Для Каждого ОписаниеРеквизита Из ОписаниеРеквизитов Цикл
Сообщить(" " + ОписаниеРеквизита);
КонецЦикла;
Иначе
Сообщить("Форма или документ не найдены, или у формы нет реквизитов.");
КонецЕсли;
КонецПроцедуры
Этот подход позволяет анализировать структуру формы, но не дает доступа к текущим значениям реквизитов незапущенной или произвольной формы на сервере, так как эти значения существуют только в контексте открытой формы.
Платформа 1С:Предприятие не предоставляет прямого и стандартного механизма для получения текущих значений реквизитов формы, которая не открыта или не находится в активном серверном контексте. Если требуется получить значения реквизитов формы без ее визуального открытия, обычно применяются обходные пути, которые мы сейчас подробно рассмотрим.
Один из способов, если вам нужно периодически или однократно получать значения реквизитов формы для последующей работы на сервере, — это сохранять их в РегистрСведений.
РегистрСведений. Этот регистр может хранить данные по пользователю, по форме, по конкретному объекту и т.д.Этот подход подходит, если данные реквизитов формы не меняются слишком часто или если небольшая задержка между изменением и доступностью на сервере допустима. Он также полезен для хранения настроек формы для конкретного пользователя.
// Пример структуры регистра сведений "НастройкиФормПользователей"
// Измерения: Пользователь (Справочник.Пользователи), ИмяФормы (Строка), ИмяРеквизита (Строка)
// Ресурсы: ЗначениеРеквизита (Тип: Характеристика, чтобы хранить разные типы данных)
// В модуле формы (НаСервере или НаКлиенте с вызовом НаСервере)
&НаСервере
Процедура СохранитьРеквизитыФормыВРегистр()
НаборЗаписей = РегистрыСведений.НастройкиФормПользователей.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Пользователь.Установить(Пользователи.ТекущийПользователь());
НаборЗаписей.Отбор.ИмяФормы.Установить("МояФормаДокумента"); // Или ЭтаФорма.Имя
// Пример сохранения нескольких реквизитов
Запись = НаборЗаписей.Добавить();
Запись.Пользователь = Пользователи.ТекущийПользователь();
Запись.ИмяФормы = "МояФормаДокумента";
Запись.ИмяРеквизита = "МойРеквизит1";
Запись.ЗначениеРеквизита = ЭтаФорма.МойРеквизит1;
Запись = НаборЗаписей.Добавить();
Запись.Пользователь = Пользователи.ТекущийПользователь();
Запись.ИмяФормы = "МояФормаДокумента";
Запись.ИмяРеквизита = "МойРеквизит2";
Запись.ЗначениеРеквизита = ЭтаФорма.МойРеквизит2;
НаборЗаписей.Записать();
СообщитьНаКлиенте("Реквизиты формы сохранены в регистр.");
КонецПроцедуры
// Пример чтения реквизитов из регистра на сервере (в любом серверном модуле)
&НаСервереБезКонтекста
Функция ПолучитьЗначениеРеквизитаИзРегистра(ИмяФормы, ИмяРеквизита)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НастройкиФормПользователей.ЗначениеРеквизита
|ИЗ
| РегистрСведений.НастройкиФормПользователей КАК НастройкиФормПользователей
|ГДЕ
| НастройкиФормПользователей.Пользователь = &Пользователь
| И НастройкиФормПользователей.ИмяФормы = &ИмяФормы
| И НастройкиФормПользователей.ИмяРеквизита = &ИмяРеквизита";
Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());
Запрос.УстановитьПараметр("ИмяФормы", ИмяФормы);
Запрос.УстановитьПараметр("ИмяРеквизита", ИмяРеквизита);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.ЗначениеРеквизита;
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
Если задача состоит в получении *структуры* форм (метаданных) для анализа, и это не требуется постоянно, а достаточно разово или по расписанию, можно использовать следующий подход:
РегистрСведений 1С.Этот вариант является достаточно сложным и применяется для задач, связанных с анализом метаданных конфигурации, а не с текущими значениями реквизитов открытой формы. Он не предоставляет способ получить *значения* реквизитов формы, которая не открыта.
Этот вариант является самым сложным и требует глубоких знаний внутренней структуры базы данных 1С, что связано с риском нарушения целостности данных и потерей поддержки со стороны 1С. Мы рассмотрим его исключительно в ознакомительных целях, но категорически не рекомендуем использовать его в реальных проектах.
Суть в том, чтобы читать файлы, описывающие метаданные, напрямую из таблиц базы данных 1С (например, таблица Config, Params). Эти файлы упакованы (например, deflate) и имеют специфический внутренний формат.
*.si из таблицы Params: В этом файле содержатся имена записей в таблице Config (метаданных) и GUID типа объекта метаданных.Config (формы в этой таблице могут иметь постфикс ".0").Этот метод является крайне низкоуровневым, не поддерживается платформой и требует постоянной адаптации при обновлении версий 1С. Он может быть оправдан только в очень специфических задачах, где все другие варианты неприемлемы.
Мы с вами подробно рассмотрели различные подходы к получению реквизитов формы на сервере в 1С:Предприятии.
&НаСервере) для полного доступа к ЭтаФорма, или внеконтекстные вызовы (&НаСервереБезКонтекста) с явной передачей параметров для оптимизации производительности.Метаданные.РегистрСведений.Всегда выбирайте наиболее простой и поддерживаемый платформой способ, который соответствует вашей задаче и обеспечивает необходимую производительность.
← К списку