Почему при изменении типа измерения регистра сведений возникает ошибка неуникальности записей и как это исправить?

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

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

Выясним причину ошибки: механизм реструктуризации данных

Для начала проанализируем ситуацию с точки зрения системы управления базами данных (СУБД). Любой Регистр сведений обладает свойством уникальности, которое обеспечивается совокупностью его измерений (и периода, если регистр периодический). На уровне SQL-таблицы это выглядит как уникальный индекс, включающий все поля измерений.

Когда мы меняем тип измерения, например, со Строки на СправочникСсылка, платформа 1С выполняет процедуру реструктуризации. Процесс выглядит следующим образом:

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

Рассмотрим пример. Допустим, в регистре были две записи:

После смены типа на ссылочный, система попытается записать в новую таблицу следующие данные:

Поскольку измерения стали идентичными, СУБД блокирует запись из-за нарушения уникальности индекса. Именно это вызывает ошибку "Неуникальная запись в регистре сведений".

Анализируем влияние владельцев справочников

Иногда разработчики связывают проблему с иерархией владельцев справочников. Рассмотрим структуру: Области -> Районы -> Города -> Улицы. Если справочник Улицы имеет несколько возможных владельцев, это усложняет логику выбора данных в интерфейсе, но напрямую не влияет на техническую уникальность записей в регистре. Уникальность определяется исключительно значениями, хранящимися в полях, а не правилами подчиненности справочников в метаданных.

Решение проблемы методом "двух проходов"

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

Шаг 1: Добавление нового измерения

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

Шаг 2: Программный перенос данных

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


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

Шаг 3: Удаление старого измерения

После того как все данные успешно перенесены в УлицаСсылка, мы можем зайти в конфигуратор и удалить старое строковое измерение Улица. Затем переименовываем УлицаСсылка обратно в Улица. Снова обновляем базу данных. Теперь структура соответствует нашим требованиям, и данные сохранены.

Альтернативное решение: Очистка регистра

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

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

РегистрыСведений.ИмяВашегоРегистра.СоздатьНаборЗаписей().Записать(Истина);

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

Важные нюансы при работе с периодичностью и составом ключа

Проанализируем еще несколько моментов, которые могут повлиять на уникальность:

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

← На главную