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

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

При проектировании интерфейсов в 1С:Предприятии 8 часто возникает необходимость связать две таблицы значений (или табличные части) на форме по принципу «один ко многим» или «многие ко многим». Классический пример: в первой таблице выводятся группы или категории товаров, а во второй — детальный состав выбранной группы. Связующим звеном между ними выступает специальное поле — ключ связи.

Сложность возникает в тот момент, когда пользователю разрешают вручную редактировать этот ключ в первой таблице. Разберем ситуацию из практики: колонка первой таблицы содержит строковый ключ. При его изменении нам нужно мгновенно обновить этот же ключ у всех подчиненных строк во второй таблице. Но как только срабатывает стандартное событие ПриИзменении, старого значения в редактируемой строке уже нет — там записано новое. А в событии ПередНачаломИзменения еще нет нового значения, которое ввел пользователь. Как найти связанные строки во второй таблице по старому ключу и обновить их?

В этой статье мы подробно рассмотрим несколько надежных способов решения этой задачи: от использования временных переменных формы до промышленных стандартов проектирования интерфейсов в 1С.

---

Способ 1. Метод «зеркальной» скрытой колонки (наиболее надежный способ)

Этот подход считается самым устойчивым к ошибкам и не зависит от фокуса ввода или перекликивания строк пользователем. Суть метода заключается в добавлении вспомогательной служебной колонки в первую таблицу значений.

Проанализируем алгоритм реализации этого метода по шагам:

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

Посмотрим на пример программной реализации этого обработчика:


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

Преимущества метода: Полная автономность каждой строки. Значения хранятся непосредственно в данных формы, что исключает сбои при быстрой смене фокуса строк или при работе в веб-клиенте.

---

Способ 2. Использование промышленного стандарта (скрытый UUID)

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

Вместо этого применяется подход со скрытым уникальным идентификатором:

Рассмотрим, как правильно инициализировать такой идентификатор при добавлении новой строки в Таблица1:


&НаКлиенте
Процедура Таблица1ПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    
    Если НоваяСтрока Тогда
        ТекущиеДанные = Элементы.Таблица1.ТекущиеДанные;
        Если ТекущиеДанные <> Неопределено Тогда
            // Генерируем уникальный ключ связи
            ТекущиеДанные.ИдентификаторСвязи = Новый УникальныйИдентификатор;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

При добавлении подчиненных строк во вторую таблицу мы просто копируем туда значение ИдентификаторСвязи из активной строки первой таблицы. Данный подход гарантирует 100% надежность и исключает необходимость сложных алгоритмов "переименования" ключей.

---

Способ 3. Перехват старого значения в переменных модуля формы

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

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

Проанализируем программный код:


&НаКлиенте
Перем ПредыдущееЗначениеКлюча; // Глобальная переменная на клиенте для хранения старого ключа

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

&НаКлиенте
Процедура Таблица1КлючСвязиПриИзменении(Элемент)
    
    ТекущиеДанные = Элементы.Таблица1.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    НовоеЗначениеКлюча = ТекущиеДанные.КлючСвязи;
    
    // Если значение не изменилось, ничего не делаем
    Если НовоеЗначениеКлюча = ПредыдущееЗначениеКлюча Тогда
        Возврат;
    КонецЕсли;
    
    // Ищем связанные строки во второй таблице по сохраненной переменной
    Для Каждого СтрокаТЗ2 Из Таблица2 Цикл
        Если СтрокаТЗ2.КлючСвязи = ПредыдущееЗначениеКлюча Тогда
            СтрокаТЗ2.КлючСвязи = НовоеЗначениеКлюча;
        КонецЕсли;
    КонецЦикла;
    
    // КРИТИЧЕСКИ ВАЖНО: Обновляем глобальную переменную новым значением.
    // Если пользователь решит изменить этот же ключ еще раз в этой же строке,
    // не переходя на другие строки, переменная должна содержать уже обновленный ключ!
    ПредыдущееЗначениеКлюча = НовоеЗначениеКлюча;
    
КонецПроцедуры

Важный нюанс: Этот способ требует повышенной внимательности разработчика. Если в коде присутствуют программные переключения фокуса строк или формы обновляются в фоновом режиме, переменная ПредыдущееЗначениеКлюча может очиститься или принять неактуальное значение. Рекомендуется использовать этот метод только в простых формах.

---

Способ 4. Перехват ввода через события «ОбработкаВыбора» и «ОкончаниеВводаТекста»

Еще один профессиональный способ получить старое и новое значения одновременно — перехватить ввод до того, как данные физически запишутся в строку таблицы на форме. Для этого используются события элементов управления (полей ввода).

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


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

Если же поле текстовое и пользователь вбивает ключ вручную с клавиатуры, аналогичную схему можно реализовать через событие ОкончаниеВводаТекста. В нем старое значение по-прежнему доступно в текущих данных строки, а новое передается в параметре Текст обработчика события.

---

Подведем итоги

Мы рассмотрели четыре различных подхода к решению классической задачи синхронизации связанных таблиц в 1С. Выбор конкретного метода зависит от архитектуры вашей конфигурации:

  1. Используйте метод зеркальной колонки (Способ 1) как стандартный и наиболее отказоустойчивый для большинства повседневных задач.
  2. Стремитесь внедрять скрытые UUID (Способ 2) при проектировании сложных систем с нуля. Это убережет код от лишних пересчетов и обеспечит максимальное быстродействие интерфейса.
  3. Применяйте сохранение в переменную (Способ 3) или перехват событий ввода (Способ 4), если возможности изменения структуры таблиц ограничены требованиями типовой конфигурации.
← На главную