При обновлении конфигурации «1С:Розница» (или любых других типовых решений на платформе 1С:Предприятие) администраторы и программисты нередко сталкиваются с критической ошибкой реструктуризации базы данных вида «Хранилище файлов: Неуникальное измерение». При этом утилита chdbfl сообщает: «Обнаружено дублирование ключевых значений в колонках», а штатное «Тестирование и исправление» завершается аварийно или не дает никакого эффекта.
Если мы выполним запрос к проблемной таблице, то увидим строки, в которых ключевое поле (измерение) содержит значение NULL. Попытки удалить такие строки напрямую через форму списка или при помощи точечного отбора в наборе записей ни к чему не приводят: платформа просто не может идентифицировать строки для удаления. Разберем детально, почему возникает эта ошибка и какими способами ее можно гарантированно устранить.
Важное предупреждение: перед выполнением любых действий по исправлению данных обязательно создайте полную резервную копию базы данных (выгрузку в .dt или копию файла .1CD / бэкап средствами СУБД) и проводите все операции сначала на тестовой копии.
Проанализируем природу проблемы: почему в измерении регистра появляется NULL и почему его нельзя удалить обычной установкой отбора?
NULL на уровне базы данных.НаборЗаписей свойство Отбор не поддерживает установку значения NULL (оно существует только в языке запросов платформы). Поэтому стандартные конструкции поиска и удаления по отбору здесь бессильны.Рассмотрим наиболее простой и надежный программный способ. Его суть заключается в том, чтобы прочитать всю таблицу регистра в память, удалить из полученного массива строк все невалидные записи, полностью очистить регистр в базе данных и затем загрузить очищенный массив обратно.
Разберем по шагам алгоритм решения с помощью внешней обработки:
Прочитать(), чтобы выгрузить все существующие записи в коллекцию.Посмотрим на пример программного кода:
НаборДанных = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
НаборДанных.Прочитать();
Индекс = НаборДанных.Количество() - 1;
Пока Индекс >= 0 Цикл
ТекущаяЗапись = НаборДанных[Индекс];
// Проверяем измерение на пустое значение или битую ссылку
Если Не ЗначениеЗаполнено(ТекущаяЗапись.ВладелецФайла) Тогда
НаборДанных.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
// Полная очистка регистра в базе
ОчищающийНабор = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
ОчищающийНабор.ОбменДанными.Загрузка = Истина;
ОчищающийНабор.Записать();
// Возврат корректных данных
НаборДанных.ОбменДанными.Загрузка = Истина;
НаборДанных.Записать();
Установка свойства ОбменДанными.Загрузка = Истина критически важна: она отключает платформенные проверки логической целостности и сопутствующие подписки на события при записи данных.
Если записей в регистре слишком много и попытка прочитать их все в оперативную память вызывает переполнение, применим другой проверенный подход — использование стандартной обработки «Выгрузка и загрузка данных XML» (или механизмов конвертации данных).
Разберем по шагам этот способ:
ХранилищеФайлов).NULL).<Record> с пустыми ключевыми полями.Если база работает под управлением Microsoft SQL Server или PostgreSQL, а доступ к конфигуратору заблокирован из-за незавершенной реструктуризации, мы можем устранить дубликаты непосредственно на уровне таблиц базы данных.
ПолучитьСтруктуруХраненияБазыДанных() определяем имя таблицы регистра в СУБД (например, _InfoRgXXXX) и наименование колонки измерения.NULL:
DELETE FROM _InfoRgXXXX
WHERE _FldXXXX_RRef IS NULL;
Рассмотрим альтернативный способ обхода коллизии уникальности, когда база данных доступна для редактирования структуры метаданных:
Строка(10)).Таким образом, комбинируя перезапись через пустой набор записей или используя выгрузку XML, удается быстро устранить блокирующие строки и успешно завершить процедуру обновления конфигурации.