При выполнении типового обновления конфигурации «1С:Бухгалтерия предприятия» на этапе реструктуризации таблиц базы данных администраторы и программисты нередко сталкиваются с критической ошибкой: «ХранилищеФайлов. Имеются записи с одинаковыми измерениями». При этом процесс обновления базы прерывается, а штатный запуск системы в пользовательском режиме становится невозможным до исправления коллизии.
Разберем природу возникновения этой проблемы, выясним, почему стандартные попытки очистки регистра могут не давать результата, и подробно рассмотрим пошаговые методы устранения ошибки.
Проанализируем техническую сторону процесса обновления. Регистр сведений ХранилищеФайлов (или аналогичный ему в Библиотеке стандартных подсистем — ДвоичныеДанныеФайлов) предназначен для хранения содержимого присоединенных файлов в базе данных. Ключевым измерением регистра является Файл, имеющее составной тип данных (ссылки на различные справочники присоединенных файлов или определяемый тип ПрисоединенныйФайл).
Коллизия возникает по одной из следующих причин:
NULL или пустая ссылка неопределенного типа). Если таких записей в регистре две или более, они объединяются под одним и тем же ключом записи, что приводит к нарушению уникальности индекса.NULL в измерении. Установить отбор через объект Отбор по значению NULL платформа не позволяет, из-за чего стандартные скрипты точечной очистки набора записей завершаются без результата.Рассмотрим распространенную ошибку при написании запроса для поиска дублей. Если использовать агрегатную функцию КОЛИЧЕСТВО(Поле), платформа 1С автоматически исключит строки со значением NULL из подсчета. В результате запрос покажет, что дублей нет, хотя СУБД видит конфликт.
Чтобы обнаружить все записи, включая пустые и некорректные, используем подсчет всех строк через КОЛИЧЕСТВО(*):
ВЫБРАТЬ
Регистр.Файл КАК Файл,
КОЛИЧЕСТВО(*) КАК КоличествоСтрок
ИЗ
РегистрСведений.ХранилищеФайлов КАК Регистр
СГРУППИРОВАТЬ ПО
Регистр.Файл
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
Также проверим регистр на наличие строк, где измерение не заполнено или содержит неразрешенные ссылки:
ВЫБРАТЬ
Регистр.Файл КАК Файл
ИЗ
РегистрСведений.ХранилищеФайлов КАК Регистр
ГДЕ
Регистр.Файл ЕСТЬ NULL
ИЛИ Регистр.Файл.Ссылка ЕСТЬ NULL
Если в результате запроса мы увидели строки со значением NULL или пустые ссылки, именно они блокируют применение изменений конфигурации.
Разберем оригинальный и надежный способ устранения дублей, когда требуется сохранить остальные рабочие данные регистра. Поскольку удалить строки с NULL через отбор невозможно, мы можем прочитать все записи регистра в память, найти строки с незаполненным измерением и программно присвоить им ссылки на новые уникальные элементы справочника.
Выполним процедуру по шагам:
РегистрСведенийНаборЗаписей, найдем незаполненные строки и перезапишем в них измерение Файл созданными ссылками.Посмотрим на пример программного кода для реализации этого алгоритма:
// Ссылки на заранее созданные фиктивные файлы
МассивФайлов = Новый Массив;
МассивФайлов.Добавить(ФайлЗаглушка1);
МассивФайлов.Добавить(ФайлЗаглушка2);
НаборЗаписей = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
НаборЗаписей.Прочитать();
Индекс = 0;
Для Каждого Запись Из НаборЗаписей Цикл
Если НЕ ЗначениеЗаполнено(Запись.Файл) Тогда
Если Индекс < МассивФайлов.Количество() Тогда
Запись.Файл = МассивФайлов[Индекс];
Индекс = Индекс + 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
НаборЗаписей.Записать();
После записи набора каждое измерение станет уникальным, дубли исчезнут, и реструктуризация в конфигураторе (клавиша F7) пройдет успешно. После завершения обновления временные файлы можно пометить на удаление и удалить стандартной обработкой.
Если записей с поврежденными ссылками много или предыдущий способ реализовать неудобно, разберем универсальный вариант с временным экспортом бинарных данных через механизм сериализации.
Выполним следующие действия по шагам:
СериализаторXDTO во внешней обработке:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\Temp\ХранилищеФайлов.xml");
Набор = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
Набор.Прочитать();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Набор);
ЗаписьXML.Закрыть();
Набор = РегистрыСведений.ХранилищеФайлов.СоздатьНаборЗаписей();
Набор.Записать();
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\Temp\ХранилищеФайлов.xml");
НаборЗагрузки = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
// Оставляем только строки с заполненным измерением
ИндексСтроки = НаборЗагрузки.Количество() - 1;
Пока ИндексСтроки >= 0 Цикл
ТекущаяЗапись = НаборЗагрузки[ИндексСтроки];
Если НЕ ЗначениеЗаполнено(ТекущаяЗапись.Файл) Тогда
НаборЗагрузки.Удалить(ИндексСтроки);
КонецЕсли;
ИндексСтроки = ИндексСтроки - 1;
КонецЦикла;
НаборЗагрузки.Записать();
В файловых базах данных (формат .1CD) описанная проблема часто усугубляется рассинхронизацией физических таблиц и их индексов. Прежде чем выполнять ручные манипуляции с данными, обязательно выполним диагностику базы данных:
.dt или прямое копирование файла 1Cv8.1CD при выключенных процессах платформы).chdbfl.exe, которая находится в каталоге установки платформы (папка bin), и выполним проверку с включенной опцией «Исправлять обнаруженные ошибки».Штатный механизм тестирования и исправления выявит висящие записи регистра, очистит неразрешимые ссылки и приведет индексы таблицы в согласованное состояние, что позволит завершить процесс реструктуризации штатно.