В процессе командной разработки часто возникает ситуация, когда структура объектов метаданных меняется. Одна из таких типовых задач — удаление ненужного измерения из регистра сведений. Разработчик вносит изменение, помещает конфигурацию в хранилище, и все кажется в порядке. Однако проблемы начинаются, когда другой разработчик или системный администратор пытается обновить рабочую базу (или ее копию) из хранилища. В момент реструктуризации базы данных платформа прерывает процесс с ошибкой "Имеются записи с одинаковыми измерениями". При этом проверка данных в самой 1С, как правило, никаких дублей не находит. Давайте подробно разберем, почему так происходит и как правильно решать эту проблему.
На первый взгляд, ситуация кажется парадоксальной. Вы уверены, что в регистре нет записей с одинаковыми измерениями, но платформа утверждает обратное. Ключ к пониманию кроется в том, как платформа выполняет реструктуризацию таблицы базы данных.
Представим исходную структуру регистра сведений:
Организация)Контрагент)Договор - то, которое мы удаляем)В базе могли существовать две записи, которые были уникальны благодаря третьему измерению:
Когда вы удаляете измерение Договор из конфигурации и применяете эти изменения к базе данных, платформа пытается перестроить SQL-таблицу. С точки зрения новой структуры, где остались только измерения Организация и Контрагент, обе эти записи становятся абсолютно идентичными:
Уникальный ключ (индекс) регистра сведений не допускает таких совпадений. Поэтому в момент, когда SQL-сервер пытается применить новый индекс к существующим данным, он обнаруживает дубли и возвращает ошибку, которую платформа 1С и транслирует вам. Ошибка возникает не на уровне логики 1С, а на физическом уровне СУБД в процессе выполнения команды ALTER TABLE.
Проблема усугубляется тем, что стандартные средства, такие как "Тестирование и исправление" (ТиИ) или запросы внутри 1С, могут не находить эти дубли, так как они работают с текущей (старой) структурой данных, где записи все еще уникальны.
Самый корректный и системный подход, предусмотренный стандартами разработки 1С, — это использование обработчиков обновления. Разработчик, который вносит изменение в структуру данных, должен также позаботиться о том, как существующие данные будут преобразованы под новую структуру.
Суть метода: вы пишете специальную процедуру, которая выполнится до того, как платформа начнет физически изменять таблицы в базе данных. В этой процедуре вы должны проанализировать данные и устранить потенциальные дубли.
Разберем по шагам:
ПриОбновленииИнформационнойБазы(). Внутри нее, на основе номера версии конфигурации, вызываются другие процедуры.Посмотрим на примерный код, который находит и удаляет дубли, оставляя одну запись.
// Процедура должна находиться в общем модуле, вызываемом из обработчика обновления
Процедура ОбработатьДублиВРегистреСведений() Экспорт
// Запрос для поиска будущих дублей по тем измерениям, которые остаются
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| т.Измерение1 КАК Измерение1,
| т.Измерение2 КАК Измерение2,
| КОЛИЧЕСТВО(т.Измерение1) КАК Количество
|ИЗ
| РегистрСведений.МойРегистр КАК т
|
|СГРУППИРОВАТЬ ПО
| т.Измерение1,
| т.Измерение2
|
|ИМЕЮЩИЕ
| КОЛИЧЕСТВО(т.Измерение1) > 1";
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
// Для каждой группы дублей получаем все записи
НаборЗаписейДляУдаления = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
НаборЗаписейДляУдаления.Отбор.Измерение1.Установить(Результат.Измерение1);
НаборЗаписейДляУдаления.Отбор.Измерение2.Установить(Результат.Измерение2);
НаборЗаписейДляУдаления.Прочитать();
// Удаляем все записи, кроме первой
Если НаборЗаписейДляУдаления.Количество() > 1 Тогда
Для сч = НаборЗаписейДляУдаления.Количество() - 1 По 1 Цикл
НаборЗаписейДляУдаления.Удалить(сч);
КонецЦикла;
// Записываем набор, в котором осталась только одна запись
НаборЗаписейДляУдаления.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот подход гарантирует, что при обновлении конфигурации на любой базе (разработчика, тестовой, рабочей) данные будут автоматически подготовлены, и ошибка не возникнет.
Этот метод применяется в том случае, если "автор" изменений не написал обработчик обновления, а вам нужно срочно обновить базу. По сути, вы выполняете работу обработчика вручную.
Порядок действий:
Это более радикальный, но очень надежный способ. Он подходит, когда логика обработки дублей сложна или когда нужно гарантированно "очистить" структуру.
РегистрыСведений.МойРегистр.СоздатьНаборЗаписей(), который затем записывается без отборов и записей, или методом Очистить().Этот метод гарантирует, что в новую структуру попадут только корректные, уникальные данные.
Иногда проблема может быть более тонкой. Вот несколько дополнительных направлений для диагностики:
-- Примерный запрос для MS SQL Server
SELECT
[_Fld123_RRef], -- Поле, соответствующее Измерению1
[_Fld456_RRef], -- Поле, соответствующее Измерению2
COUNT(*) as Cnt
FROM
dbo._InfoRg789 -- Имя таблицы вашего регистра
GROUP BY
[_Fld123_RRef],
[_Fld456_RRef]
HAVING
COUNT(*) > 1
В заключение, отметим, что очистка регистра, как это сделал автор темы, — это крайняя мера, ведущая к потере данных. Она применима только для вспомогательных, некритичных регистров. В большинстве случаев следует использовать более системные подходы, описанные выше, чтобы сохранить целостность и историю данных.