Как исправить ошибку «Неуникальное измерение» с NULL в регистре сведений при обновлении 1С?

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

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

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

Важное предупреждение: перед выполнением любых действий по исправлению данных обязательно создайте полную резервную копию базы данных (выгрузку в .dt или копию файла .1CD / бэкап средствами СУБД) и проводите все операции сначала на тестовой копии.

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

  1. Усечение типов данных в метаданных: Измерение регистра сведений часто имеет составной тип. Если разработчик при очередном релизе удаляет один из типов (например, устаревший справочник) или в базе ранее были удалены объекты без контроля ссылочной целостности («битые ссылки»), при реструктуризации платформа не может сопоставить тип и заменяет ссылку на NULL на уровне базы данных.
  2. Дублирование в уникальном индексе: Если таких некорректных записей две или более, они схлопываются в одинаковый набор ключевых полей. СУБД не может перестроить уникальный индекс таблицы регистра, и процесс обновления блокируется.
  3. Ограничение отбора 1С: В объектной модели НаборЗаписей свойство Отбор не поддерживает установку значения NULL (оно существует только в языке запросов платформы). Поэтому стандартные конструкции поиска и удаления по отбору здесь бессильны.

Способ 1. Программная перезапись регистра через выгрузку в память

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

Разберем по шагам алгоритм решения с помощью внешней обработки:

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

Посмотрим на пример программного кода:


НаборДанных = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
НаборДанных.Прочитать();

Индекс = НаборДанных.Количество() - 1;
Пока Индекс >= 0 Цикл
    ТекущаяЗапись = НаборДанных[Индекс];
    // Проверяем измерение на пустое значение или битую ссылку
    Если Не ЗначениеЗаполнено(ТекущаяЗапись.ВладелецФайла) Тогда
        НаборДанных.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

// Полная очистка регистра в базе
ОчищающийНабор = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
ОчищающийНабор.ОбменДанными.Загрузка = Истина;
ОчищающийНабор.Записать();

// Возврат корректных данных
НаборДанных.ОбменДанными.Загрузка = Истина;
НаборДанных.Записать();

Установка свойства ОбменДанными.Загрузка = Истина критически важна: она отключает платформенные проверки логической целостности и сопутствующие подписки на события при записи данных.

Способ 2. Выгрузка и загрузка данных с предварительной фильтрацией

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

Разберем по шагам этот способ:

  1. Открываем обработку «Выгрузка и загрузка данных XML».
  2. В дереве выгружаемых метаданных отмечаем только один проблемный регистр сведений (например, ХранилищеФайлов).
  3. Настраиваем отбор при выгрузке: выгружаем только те строки, у которых ключевые измерения заполнены корректно (отсекая строки с пустыми значениями и NULL).
  4. Выгружаем данные в XML-файл на диск. Если настроить фильтр в обработке не удается, можно выгрузить регистр целиком, открыть результирующий XML-файл в текстовом редакторе и вручную удалить блоки <Record> с пустыми ключевыми полями.
  5. Очищаем регистр сведений в информационной базе полностью (записью пустого набора записей без отбора).
  6. Загружаем исправленный файл обратно через ту же обработку в режиме предприятия.

Способ 3. Прямое удаление на уровне СУБД (для клиент-серверного варианта)

Если база работает под управлением Microsoft SQL Server или PostgreSQL, а доступ к конфигуратору заблокирован из-за незавершенной реструктуризации, мы можем устранить дубликаты непосредственно на уровне таблиц базы данных.

  1. С помощью встроенной функции ПолучитьСтруктуруХраненияБазыДанных() определяем имя таблицы регистра в СУБД (например, _InfoRgXXXX) и наименование колонки измерения.
  2. Выполняем прямой SQL-запрос на удаление записей, содержащих NULL:
    
    DELETE FROM _InfoRgXXXX 
    WHERE _FldXXXX_RRef IS NULL;
    
  3. После выполнения запроса перезапускаем службу сервера «1С:Предприятия», чтобы очистить серверный кэш метаданных, и повторно запускаем процесс обновления в конфигураторе.

Способ 4. Временное расширение измерений в конфигураторе

Рассмотрим альтернативный способ обхода коллизии уникальности, когда база данных доступна для редактирования структуры метаданных:

  1. Включаем возможность изменения конфигурации, если она находится на полной поддержке.
  2. Добавляем в проблемный регистр сведений временное измерение любого типа (например, Строка(10)).
  3. Применяем изменения (F7). Так как в составной уникальный ключ регистра добавилось новое измерение, коллизия исчезает, и реструктуризация таблицы завершается успешно.
  4. Заходим в пользовательский режим «1С:Предприятие», спокойно удаляем или перезаписываем строки с некорректными измерениями.
  5. Возвращаемся в конфигуратор, удаляем временное измерение, снова применяем конфигурацию и возвращаем объект на типовую поддержку.

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

← На главную