Как изменить значение реквизита справочника через дерево значений в документе?

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

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

В этой статье мы подробно разберем, как реализовать механизм прямой записи данных в справочник из интерфейса дерева значений документа, проанализируем архитектурные нюансы и обеспечим корректную работу системы с точки зрения транзакций и прав доступа.

Разбор архитектурной задачи

Прежде всего, нам необходимо понять, как данные попадают в дерево значений. Обычно это происходит при открытии документа или по нажатию кнопки «Заполнить». В этот момент данные считываются из базы данных (из справочника) и визуализируются на форме. Однако стоит помнить: дерево значений на форме — это лишь копия данных в оперативной памяти. Изменение флажка в строке дерева само по себе никак не влияет на реальный объект в базе данных, пока мы не напишем соответствующий код.

Для решения задачи нам потребуется:

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

Шаг 1: Подготовка данных в дереве значений

Рассмотрим, как изначально заполняется дерево. Важно, чтобы в структуре дерева была колонка, содержащая Ссылку на объект справочника. Без ссылки мы не сможем найти нужный объект в базе для редактирования.

Проанализируем пример кода заполнения дерева из запроса:


&НаСервере
Процедура ЗаполнитьДеревоПомещений()
    ДеревоПомещений.ПолучитьЭлементы().Очистить();
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Объекты.Ссылка КАК Помещение,
        |   Объекты.НаучныйФонд КАК НаучныйФонд
        |ИЗ
        |   Справочник.ЦБУ_ОбъектыНедвижимости КАК Объекты
        |ГДЕ
        |   Объекты.Ссылка В(&МассивСсылок)";
    
    Запрос.УстановитьПараметр("МассивСсылок", Объект.СписокПомещений.ВыгрузитьКолонку("Помещение"));
    
    РезультатЗапроса = Запрос.Выполнить();
    // Далее следует обход выборки и заполнение иерархии дерева...
КонецПроцедуры

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

Шаг 2: Реализация клиент-серверного взаимодействия

Чтобы изменение флажка сразу записывалось в базу, используем событие ПриИзменении для элемента формы, который отображает реквизит НаучныйФонд в дереве значений.

На стороне клиента нам нужно получить данные текущей строки. Рассмотрим, как это сделать правильно:


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

Обратите внимание: мы используем свойство ТекущиеДанные. Оно позволяет обратиться к полям той строки, в которой пользователь только что нажал на чекбокс.

Шаг 3: Объектная запись на сервере

Теперь перейдем к самому ответственному моменту — работе с данными на сервере. Чтобы изменить реквизит в базе, нам нужно превратить ссылку в объект с помощью метода ПолучитьОбъект().

Проанализируем серверную процедуру:


&НаСервере
Процедура ДеревоПомещенийНаучныйФондПриИзмененииНаСервере(СсылкаНаОбъект, НовоеЗначениеФонда)
    // Получаем объект для редактирования
    ОбъектСправочника = СсылкаНаОбъект.ПолучитьОбъект();
    
    Если ОбъектСправочника <> Неопределено Тогда
        // Устанавливаем новое значение реквизита
        ОбъектСправочника.НаучныйФонд = НовоеЗначениеФонда;
        
        Попытка
            // Записываем изменения в базу данных
            ОбъектСправочника.Записать();
            
            // Сообщаем системе, что справочник изменился, 
            // чтобы другие формы могли обновиться
            ОповеститьОбИзменении(СсылкаНаОбъект);
        Исключение
            // Обработка ошибок (например, если объект заблокирован другим пользователем)
            ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
            ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось сохранить изменения: " + ТекстОшибки);
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

Важные технические нюансы

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

1. Блокировки данных

Метод Записать() может вызвать исключение, если справочник в данный момент открыт и редактируется другим пользователем. Именно поэтому мы обязательно используем конструкцию Попытка...Исключение. В промышленном коде также рекомендуется проверять, заблокирован ли объект, прежде чем пытаться его записать.

2. Права доступа

У пользователя могут быть права на создание документа, но могут отсутствовать права на изменение справочника "Объекты недвижимости". В этом случае ОбъектСправочника.Записать() выдаст ошибку доступа. Если бизнес-логика требует, чтобы запись прошла в любом случае, процедуру следует вынести в привилегированный модуль или использовать команду УстановитьПривилегированныйРежим(Истина).

3. Синхронизация интерфейса

После вызова Записать() данные в базе изменились. Если у пользователя открыт этот справочник в отдельном окне, он должен увидеть актуальные данные. Для этого мы добавили вызов ОповеститьОбИзменении(СсылкаНаОбъект). Это стандартный механизм платформы для обновления динамических списков и форм.

4. Режим редактирования колонки

Чтобы событие ПриИзменении срабатывало мгновенно при клике на галочку, убедитесь, что в свойствах колонки дерева значений в конфигураторе установлено свойство РежимРедактирования в значение Вход при вводе. Это избавит пользователя от необходимости делать лишний клик для активации ячейки.

Альтернативный подход: Отложенная запись

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

Такой подход снижает нагрузку на сервер и минимизирует количество блокировок в базе данных.

Резюме

Мы выяснили, что для записи значения из дерева в справочник достаточно получить текущую строку через Элементы.ИмяДерева.ТекущиеДанные, передать ссылку на сервер и воспользоваться стандартным методом ПолучитьОбъект(). Этот метод прост в реализации и обеспечивает высокую скорость работы пользователя, избавляя его от рутинного открытия множества форм справочников.

← На главную