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

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

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

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

Выясним причину: почему возникает ошибка неуникальности?

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

Проанализируем, что происходит при изменении структуры регистра:

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

Рассмотрим подробнее методы решения этой проблемы, разделив их на превентивные (до изменения структуры) и аварийные (когда конфигуратор уже заблокирован).

Способ 1. Профилактика с помощью запроса (рекомендуемый метод)

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

Допустим, мы планируем удалить измерение УдаляемоеИзмерение из регистра сведений ЦеныНоменклатуры. Прежде чем удалять его в конфигураторе, запустим консоль запросов в режиме Предприятия и выполним следующий запрос:


ВЫБРАТЬ
    Цены.Период КАК Период,
    Цены.Номенклатура КАК Номенклатура,
    Цены.ТипЦен КАК ТипЦен,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Цены.Актуальность) КАК КоличествоДублей
ИЗ
    РегистрСведений.ЦеныНоменклатуры КАК Цены
СГРУППИРОВАТЬ ПО
    Цены.Период,
    Цены.Номенклатура,
    Цены.ТипЦен
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Цены.Актуальность) > 1

В данном запросе мы сгруппировали записи по тем полям, которые останутся в регистре после реструктуризации. Секция ИМЕЮЩИЕ отсекает все уникальные комбинации, оставляя только те группы, где количество записей больше одной. Получив этот список, мы можем написать простую обработку, которая свернет данные (например, удалит более старые записи или просуммирует ресурсы), и только после этого приступить к изменению метаданных в Конфигураторе.

Способ 2. Использование инструментов разработчика (ИР)

Если вы не хотите писать запросы и обработчики вручную, воспользуемся специализированным инструментом. В составе известного программного комплекса «Инструменты разработчика» (ИР) есть мощная обработка — «Подготовка к изменению структуры БД».

Эта обработка работает следующим образом:

  1. Она анализирует текущие метаданные конфигурации и сравнивает их со структурой базы данных.
  2. Автоматически определяет, в каких именно регистрах сведений возникнет конфликт уникальности при обновлении.
  3. Предоставляет удобный интерфейс для автоматического или полуавтоматического «схлопывания» дубликатов по выбранным правилам (например, оставить первую запись, оставить последнюю или суммировать числовые ресурсы).

Способ 3. Аварийный откат и исправление данных

Рассмотрим ситуацию, когда изменения в Конфигураторе уже применены, кнопка «Принять» выдала ошибку неуникальности, и база данных теперь не запускается ни в каком режиме. Разберем по шагам алгоритм безопасного отката:

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

Способ 4. Временный программный код (метод «костыля» при запуске)

Если конфигурация изменена, реструктуризация «зависла» на этапе применения изменений, но платформа все же позволяет запустить базу в режиме Предприятия (или вы можете запустить ее в режиме отладки), мы можем применить временный программный код для полной очистки проблемного регистра.

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

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

Процедура ПриНачалеРаботыСистемы()
    // Временный код для принудительной очистки проблемного регистра
    НаборЗаписей = РегистрыСведений.ИмяВашегоРегистра.СоздатьНаборЗаписей();
    НаборЗаписей.Записать(Истина); // Записываем пустой набор для очистки таблицы
КонецПроцедуры

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

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

Способ 5. Очистка таблицы напрямую через СУБД (SQL)

Для клиент-серверных баз данных под управлением MS SQL Server или PostgreSQL существует радикальный, но очень быстрый способ решения проблемы — прямая очистка таблицы на уровне СУБД. Этот метод незаменим на больших базах, когда стандартный откат изменений занимает слишком много времени.

Выполним следующие шаги:

  1. Выясним имя физической таблицы нашего регистра сведений в СУБД. Для этого в Конфигураторе или через обработку выполните вызов функции ПолучитьСтруктуруХраненияБазыДанных(). Также можно найти таблицу по имени метаданных в таблице базы данных. Обычно она имеет вид _InfoRegXXXX (где XXXX — порядковый номер таблицы).
  2. Откройте консоль управления СУБД (например, SQL Server Management Studio или pgAdmin).
  3. Выполните команду очистки таблицы (операция TRUNCATE работает значительно быстрее, чем DELETE, так как не записывает каждую строку в журнал транзакций):

TRUNCATE TABLE _InfoReg1234; -- Вместо _InfoReg1234 укажите имя вашей таблицы

  1. Вернитесь в Конфигуратор 1С и запустите обновление конфигурации базы данных. Реструктуризация пройдет без ошибок.
  2. Если данные регистра необходимо сохранить, перед выполнением TRUNCATE сделайте резервную копию этой таблицы или выгрузите данные в промежуточный файл, после чего удалите дубли и загрузите обратно через стандартный объект платформы НаборЗаписей.

Способ 6. Создание нового регистра взамен старого

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

Разберем этот алгоритм:

  1. Создайте в Конфигураторе новый регистр сведений (например, НовыеЦеныНоменклатуры) с требуемой новой структурой измерений и ресурсов.
  2. Напишите обработку, которая перенесет данные из старого регистра в новый. При переносе в коде обработки опишите правила объединения дублирующихся записей. Пример переноса:

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

Мы подробно изучили все возможные варианты борьбы с неуникальными записями в регистрах сведений 1С. Помните, что залог успешного обновления — это всегда предварительный анализ данных с помощью запросов и своевременное создание резервных копий перед любыми административными действиями.

← На главную