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

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

В процессе разработки учетных систем на платформе 1С:Предприятие часто возникает задача ускорения рутинных операций пользователей. Классический сценарий — простановка признаков для большого количества позиций номенклатуры (например, флажка включения в прайс-лист, признака новинки или архивной позиции). Открывать каждый элемент справочника по отдельности долго и неудобно. В этой статье мы подробно разберем, как реализовать редактирование булевого реквизита прямо из формы списка, рассмотрим подводные камни прямого изменения объектов и изучим рекомендуемые стандарты разработки.

Способ 1. Интерактивная перезапись объекта через события табличного поля

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

Разберем по шагам порядок настройки формы:

  1. Откроем форму списка справочника в конфигураторе.
  2. В свойствах нужной колонки табличного поля установим элемент управления ПолеФлажка (или укажем свойство ДанныеФлажка).
  3. Для табличного поля назначим обработчик события ПриИзмененииФлажка.
  4. В модуле формы опишем логику считывания текущей строки, модификации объекта и обновления отображения списка.

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


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

Для обновления данных списка после изменения можно использовать метод ОбновитьСтроки(), передавая конкретную строку, либо метод источника данных Обновить(), если требуется полная синхронизация динамического списка.

Подводные камни и риски прямой записи объекта

Несмотря на внешнюю простоту и работоспособность такого подхода, он имеет существенные архитектурные недостатки, о которых важно помнить:

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

Способ 2. Оптимальное архитектурное решение через независимый регистр сведений

Рассмотрим, как правильно организовать хранение подобных оперативных пользовательских признаков согласно стандартам разработки 1С. Лучшая практика — вынос признака в непериодический независимый регистр сведений (например, СоставПрайсЛиста).

Структура такого регистра сведений выглядит следующим образом:

  1. Измерения: Номенклатура (Тип: Ссылка на справочник Номенклатура, признак «Ведущее»).
  2. Ресурсы: ВключатьВПрайс (Тип: Булево).

Выясним главные преимущества хранения признаков в регистре сведений:

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

Посмотрим на пример кода записи значения в регистр сведений при изменении флажка в табличном поле:


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

Оптимизация отображения данных регистра в обычном списке

Чтобы список номенклатуры с подключенным регистром сведений работал быстро даже на сотнях тысяч позиций, заполнение колонки флажка нужно оптимизировать. Вместо построчного события ПриВыводеСтроки (которое порождает проблему множественных запросов к базе «N+1») используем пакетное событие ПриПолученииДанных.

Рассмотрим пример правильного пакетного заполнения строк:


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

Такая связка обеспечивает максимальную производительность списков, гарантирует корректность разграничения прав пользователей и предотвращает возникновение блокировок при одновременной массовой работе.

← На главную