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

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Анализ проблемы и архитектурные ограничения платформы 1С 7.7

Выясним причину возникновения указанных ошибок при различных подходах.

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


Процедура ИзменитьВладельца()
    Владелец = Клиент;
    Записать();
КонецПроцедуры

В этот момент платформа выдает исключение «Объект не может быть перепозиционирован!». Дело в том, что открытая форма подчиненного справочника жестко привязана к контексту текущего владельца. Внутренний указатель базы данных позиционирован внутри выборки родительского элемента. Смена владельца означает физическое перемещение элемента в другую ветку подчинения, что нарушает целостность контекста уже открытой формы.

Проанализируем вторую типичную попытку: обойти контекст формы через создание отдельного объекта:


Процедура ИзменитьВладельца()
    СпрКарт = СоздатьОбъект("Справочник.КартриджиКлиента"); 
    Если СпрКарт.НайтиПоКоду(Код) = 1 Тогда
        СпрКарт.Владелец = Клиент;
        СпрКарт.Записать();
    КонецЕсли;
КонецПроцедуры

В данном сценарии возникает ошибка «Объект заблокирован». Так как форма редактирования уже открыта пользователем, платформа накладывает монопольную транзакционную блокировку на редактируемую запись справочника. Любой параллельный объект, созданный через СоздатьОбъект, не может модифицировать эту запись до тех пор, пока форма не будет закрыта.

Таким образом, выполнить смену владельца «на лету» внутри открытой формы без специальных приемов невозможно. Разберем рабочие способы реализации этой операции.

Способ 1. Изменение владельца с закрытием и переоткрытием формы

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

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

Посмотрим на пример кода внешней процедуры или обработки, принимающей ссылку на элемент и нового владельца:


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

Способ 2. Переподчинение элемента из формы списка справочника

Рассмотрим альтернативный сценарий, принятый в типовых конфигурациях 1С 7.7. Операцию смены владельца выносят в форму списка (журнал) подчиненного справочника.

В форме списка отдельная запись не заблокирована на редактирование, поэтому переподчинение выполняется штатно:

  1. Пользователь выбирает строку в списке справочника.
  2. Нажимает сервисную кнопку «Сменить владельца».
  3. В диалоге выбирает нового контрагента.
  4. Программа находит выбранную позицию через СоздатьОбъект и перезаписывает реквизит.

Посмотрим на пример реализации в модуле формы списка:


Процедура СменитьВладельцаВСписке()
    Перем НовыйКлиент;
    Если ТекущийЭлемент().Выбран() = 0 Тогда
        Предупреждение("Выберите элемент в списке!");
        Возврат;
    КонецЕсли;
    
    Если ОткрытьФормуМодально("Справочник.Клиенты", НовыйКлиент) = 1 Тогда
        Спр = СоздатьОбъект("Справочник.КартриджиКлиента");
        Если Спр.НайтиЭлемент(ТекущийЭлемент()) = 1 Тогда
            Спр.Владелец = НовыйКлиент;
            Спр.Записать();
            Форма.Обновить();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Способ 3. Создание дубликата с новым владельцем и удаление оригинала

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

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

Способ 4. Прямой SQL-запрос для баз данных на MS SQL Server

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

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


UPDATE $Справочник.КартриджиКлиента
SET PARENTEXT = :НовыйВладелец
WHERE ID = :ТекущийЭлемент

Обратите внимание: после выполнения низкоуровневого запроса открытую форму необходимо немедленно закрыть без записи (Форма.Закрыть(0)), иначе платформа при сохранении восстановит старого владельца из экранного буфера.

← На главную