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