В процессе доработки или обновления конфигураций 1С разработчики нередко сталкиваются с необходимостью изменить состав документов, формирующих движения по регистру накопления. Типичная задача: учетные движения ранее формировались документом одного вида (например, Документ1), а в новой версии логики они должны формироваться другим объектом (например, Документ2). Если просто снять отметку регистратора у старого документа и назначить новый в дереве метаданных, поведение платформы при реструктуризации базы данных может привести к критическим сбоям и нарушению целостности данных. Разберем механику работы платформы в такой ситуации, возникающие скрытые проблемы и пошаговый регламент безопасного перехода.
Поведение системы зависит от того, был ли тип стандартного реквизита Регистратор простым (одиночным) или составным:
Документ1), а разработчик сразу заменяет его на Документ2, поле регистратора в физической таблице СУБД меняет тип с одного ссылочного типа на другой. При реструктуризации платформа пытается преобразовать значения поля, но ссылки ДокументСсылка.Документ1 не могут быть приведены к типу ДокументСсылка.Документ2. Все существующие ссылки сбрасываются в пустые значения нового типа. Так как регистратор вместе с периодом и номером строки входит в кластерный уникальный индекс таблицы движений, при наличии более одной записи по регистратору возникает ошибка СУБД: «Записи регистра стали неуникальными». В результате обновление базы данных аварийно прерывается.Даже если реструктуризация завершилась успешно и движения визуально остались в регистре, прямое отключение регистратора порождает системные ошибки в режиме 1С:Предприятие:
Документ1 подчиненный регистр накопления исключается из коллекции Движения. Документ больше не связан с ранее сделанными записями: при его перепроведении, отмене проведения или непосредственном удалении записи в регистре накопления останутся без изменений, превращаясь в неуправляемые «фантомные» движения.Отбор.Регистратор.Установить() выбросит исключение «Недопустимый тип значения», так как тип ДокументСсылка.Документ1 исключен из метаданных регистратора.Чтобы исключить потерю данных и появление системных ошибок, процедуру замены регистратора необходимо выполнять по строгому регламенту в два релиза конфигурации.
Шаг 1. Расширение состава регистраторов (Релиз 1)
Открываем конфигуратор и добавляем новый Документ2 в список регистраторов регистра накопления, обязательно оставляя включенным Документ1. Применяем изменения к базе данных. В этот момент тип регистратора гарантированно становится составным, а существующие движения старых документов остаются полностью доступными для чтения и программной перезаписи.
Шаг 2. Перенос движений на новый регистратор
В пользовательском режиме запускаем внешнюю обработку или обработчик обновления. Выполняем создание новых документов или перенос движений. Разберем пример кода, выполняющего перенос движений со старого регистратора на новый с очисткой исходных записей:
Выборка = Документы.Документ1.Выбрать();
Пока Выборка.Следующий() Цикл
СсылкаСтарая = Выборка.Ссылка;
// Создаем или находим новый документ
НовыйДокОбъект = Документы.Документ2.СоздатьДокумент();
НовыйДокОбъект.Дата = СсылкаСтарая.Дата;
НовыйДокОбъект.Организация = СсылкаСтарая.Организация;
НовыйДокОбъект.Записать(РежимЗаписиДокумента.Запись);
// Считываем движения старого документа
НаборСтарый = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборСтарый.Отбор.Регистратор.Установить(СсылкаСтарая);
НаборСтарый.Прочитать();
Если НаборСтарый.Количество() > 0 Тогда
// Переносим движения в новый документ
НаборНовый = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборНовый.Отбор.Регистратор.Установить(НовыйДокОбъект.Ссылка);
Для Каждого Запись Из НаборСтарый Цикл
ЗаполнитьЗначенияСвойств(НаборНовый.Добавить(), Запись);
КонецЦикла;
НаборНовый.Записать();
// Очищаем движения старого документа для корректного пересчета итогов
НаборСтарый.Очистить();
НаборСтарый.Записать();
КонецЕсли;
КонецЦикла;
Шаг 3. Контроль остатков записей по старому типу
Перед удалением старого регистратора из метаданных обязательно проверяем отсутствие записей контрольным запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Регистр.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК Регистр
|ГДЕ
| Регистр.Регистратор ССЫЛКА Документ.Документ1";
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
ВызватьИсключение "В регистре еще остались движения со старым регистратором!";
КонецЕсли;
Шаг 4. Удаление старого регистратора (Релиз 2)
После того как все записи перенесены, а контрольный запрос подтвердил отсутствие записей с типом Документ1, открываем конфигуратор, снимаем флаг регистратора у Документ1 и применяем изменения конфигурации базы данных. Реструктуризация пройдет штатно, не нарушив уникальность индексов и целостность информационной базы.