Как решить ошибку 'Блокировку установить не удалось, поле Регистратор отсутствует' при управляемых блокировках в 1С:УПП 1.3?

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

При работе с конфигурацией 1С:УПП 1.3, особенно в измененных средах, мы можем столкнуться с ошибкой "Блокировку установить не удалось, поле Регистратор отсутствует" при попытке установить управляемую блокировку на регистр КонтролируемыеЗначенияБюджетов. Эта проблема возникает, когда код пытается заблокировать данные по полю Регистратор, которое физически отсутствует в структуре данного регистра. Давайте подробно разберем, почему возникает такая ситуация и какие варианты решения мы можем применить.

Понимание поля 'Регистратор' и механизма управляемых блокировок

Для начала, давайте освежим в памяти, что такое поле Регистратор и как работают управляемые блокировки в 1С:Предприятии 8.

  1. Поле Регистратор: Это стандартный системный реквизит, который автоматически добавляется платформой 1С в регистры, подчиненные регистратору. К таким регистрам относятся регистры накопления, регистры бухгалтерии и регистры расчета. Он хранит ссылку на документ-основание, который сформировал движения по этому регистру. Для независимых регистров сведений, таких как КонтролируемыеЗначенияБюджетов в 1С:УПП, поле Регистратор по умолчанию отсутствует, если регистр не сделан подчиненным явным образом.
  2. Управляемые блокировки: В отличие от автоматических блокировок, которые платформа устанавливает самостоятельно, управляемые блокировки дают разработчику полный контроль над тем, какие данные и каким образом будут заблокированы. Это позволяет значительно повысить параллельность работы пользователей, предотвращая конфликты при одновременной работе с одними и теми же данными. Управляемые блокировки обычно устанавливаются по набору ключевых полей (измерений) регистра, которые однозначно идентифицируют записи, подлежащие изменению.

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

Анализ типового кода и причины ошибки

Мы видим, что проблема возникает в типовом коде документа "Закрытие Заявок на расх. ДС" при попытке проведения. Рассмотрим фрагмент кода, который вызывает ошибку:


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

Давайте проанализируем этот фрагмент:

  1. СтруктураПараметровБлокировки: Здесь мы видим попытку заблокировать таблицу регистра КонтролируемыеЗначенияБюджетов. Мы также указываем источник данных (МенеджерВремТаблиц) и имя временной таблицы (ЗаявкиИЗакрытияЗаявок), которая, предположительно, содержит ссылки на документы или другие ключи для блокировки.
  2. СтруктураИсточникаДанных = Новый Структура( "Регистратор", "Ссылка");: Именно здесь кроется корень нашей проблемы. Эта структура указывает, что мы хотим установить блокировку, используя поле с именем "Регистратор" из источника данных (временной таблицы) и сопоставить его с полем "Ссылка" в блокируемой таблице регистра. Однако, в контексте функции ОбщегоНазначения.УстановитьУправляемуюБлокировку, когда мы передаем СтруктураИсточникаДанных, система ожидает, что поле "Регистратор" будет существовать в структуре самого регистра КонтролируемыеЗначенияБюджетов для сопоставления. Поскольку регистр является независимым регистром сведений, поля Регистратор в нем нет, что приводит к ошибке "Блокировку установить не удалось, поле Регистратор отсутствует".
  3. Закомментированная строка: ОбщегоНазначения.УстановитьУправляемуюБлокировку(СтруктураПараметровБлокировки, , СтруктураИсточникаДанных, Отказ, Заголовок); – это типовой код, который вызывает ошибку. Он пытается установить блокировку с использованием неверно указанного поля.
  4. Временное решение автора: ОбщегоНазначения.УстановитьУправляемуюБлокировку(СтруктураПараметровБлокировки, , , Отказ, Заголовок); – удаление третьего параметра (СтруктураИсточникаДанных) при вызове функции. Это позволило избежать ошибки, так как не было явной попытки блокировки по несуществующему полю. Однако такое решение может привести к блокировке всей таблицы регистра (если это предусмотрено логикой функции без указания полей) или к отсутствию точной блокировки, что может снизить параллельность или даже привести к нарушению целостности данных в определенных сценариях.

Таким образом, основная причина проблемы – это попытка заблокировать регистр по полю, которое в нем отсутствует. Даже если код является типовым, он может быть рассчитан на другие типы регистров или на ситуации, когда КонтролируемыеЗначенияБюджетов был бы подчиненным регистром (что не так в УПП).

Решение: Установка управляемой блокировки по измерениям или с помощью объекта 'БлокировкаДанных'

Чтобы корректно решить эту проблему, мы должны перестать пытаться блокировать по несуществующему полю Регистратор и вместо этого использовать действительные измерения регистра КонтролируемыеЗначенияБюджетов. Мы рассмотрим два основных подхода.

  1. Блокировка по измерениям регистра

    Если регистр не имеет поля Регистратор, то управляемая блокировка должна осуществляться по набору его измерений, которые уникально идентифицируют записи, подлежащие изменению или чтению. Для регистра КонтролируемыеЗначенияБюджетов это могут быть такие измерения, как Период, Организация, СтатьяБюджета, Сценарий, Подразделение и т.д. Мы должны определить, какие именно записи регистра затрагивает наш документ "Закрытие Заявок на расх. ДС", и заблокировать их по соответствующим измерениям.

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

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

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

    В этом примере мы:

    1. Подготовили временную таблицу, содержащую актуальные измерения регистра КонтролируемыеЗначенияБюджетов, которые связаны с проводкой нашего документа.
    2. Использовали объект БлокировкаДанных напрямую, что дает нам более тонкий контроль.
    3. Явно указали, что блокируем РегистрСведений.КонтролируемыеЗначенияБюджетов.НаборЗаписей.
    4. С помощью метода ИспользоватьИзИсточникаДанных сопоставили поля из нашей временной таблицы с соответствующими измерениями регистра. Это критически важный шаг, так как мы блокируем по фактическим ключам, а не по несуществующему Регистратор.
  2. Адаптация типовой функции ОбщегоНазначения.УстановитьУправляемуюБлокировку

    Если мы хотим сохранить использование типовой функции ОбщегоНазначения.УстановитьУправляемуюБлокировку, нам необходимо скорректировать СтруктураИсточникаДанных так, чтобы она отражала реальные измерения регистра, а не поле Регистратор. Однако это потребует изменения самой типовой функции ОбщегоНазначения.УстановитьУправляемуюБлокировку или создания ее аналога, который сможет принимать список полей для блокировки. Если конфигурация на поддержке, изменение типовой функции нежелательно. Поэтому более предпочтительным является первый подход с прямым использованием объекта БлокировкаДанных.

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

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

    Важно: Перед применением такого подхода мы должны убедиться, что функция ОбщегоНазначения.УстановитьУправляемуюБлокировку действительно способна корректно интерпретировать СтруктураИсточникаДанных с несколькими полями. В противном случае, более надежным является прямое использование объекта БлокировкаДанных.

Дополнительные рекомендации и проверка конфигурации

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

  1. Проверка режима управления блокировкой данных: Мы должны убедиться, что для всей конфигурации, для документа "Закрытие Заявок на расх. ДС" и для регистра КонтролируемыеЗначенияБюджетов установлен режим управления блокировкой данных "Управляемый". Если хотя бы для одного из этих объектов установлен "Автоматический" режим, попытки установки управляемых блокировок могут быть проигнорированы или привести к непредсказуемому поведению. Этот параметр находится в свойствах конфигурации, а также в свойствах отдельных объектов метаданных.
  2. Использование отладчика: Это наш лучший инструмент для понимания того, что происходит в коде. Мы можем установить точки останова в модуле документа "Закрытие Заявок на расх. ДС", непосредственно перед вызовом функции блокировки, а также внутри нее (если это возможно). Отладчик поможет нам увидеть значения всех параметров, передаваемых функции, и точно определить момент и причину возникновения ошибки.
  3. Очистка кэша: Иногда проблемы с метаданными или некорректным поведением могут быть связаны с поврежденным или устаревшим кэшем на стороне клиента или сервера. Очистка кэша (через удаление каталогов кэша 1С или с помощью утилиты `chdbfl`) часто помогает в таких случаях. Автор сообщения уже пробовал это, но об этом всегда стоит помнить.
  4. Анализ изменений конфигурации: Поскольку автор упоминает, что конфигурация "допиливалась", мы должны тщательно проанализировать все внесенные изменения, особенно в модулях документа "Закрытие Заявок на расх. ДС" и в структуре регистра КонтролируемыеЗначенияБюджетов. Возможно, были добавлены или удалены какие-либо измерения или реквизиты, что повлияло на логику работы с блокировками. Мы также должны проверить, не были ли изменены свойства самого регистра.
  5. Документирование изменений: В измененных конфигурациях крайне важно документировать все изменения кода, используя комментарии с указанием даты, имени разработчика и описания внесенных модификаций. Это значительно облегчает поддержку и обновление конфигурации в будущем.

Применение этих подходов поможет нам не только решить текущую проблему с блокировкой, но и улучшить общую стабильность и производительность нашей системы 1С:УПП 1.3.

← На главную