При разработке на платформе 1С часто возникает ситуация, когда на начальном этапе проектирования РегистрСведений создается как независимый, но со временем логика системы меняется, и записи регистра необходимо жестко привязать к документам-регистраторам. Основная проблема заключается в том, что при простом переключении режима записи в конфигураторе с "Независимый" на "Подчинение регистратору", все существующие данные в информационной базе будут безвозвратно удалены в процессе реструктуризации. Рассмотрим, почему это происходит и какими способами можно выполнить преобразование, сохранив при этом все накопленные записи.
Прежде чем мы перейдем к методам решения, проанализируем техническую сторону вопроса. В системе 1С структура таблиц СУБД для независимых и подчиненных регистров принципиально различается. Для независимого регистра ключом уникальности является только комбинация его измерений. Для подчиненного регистра платформа автоматически добавляет в структуру таблицы два обязательных системных поля: Регистратор (ссылка на документ) и НомерСтроки (целое число).
В момент принятия изменений конфигурации платформа видит изменение первичного ключа. Так как система не знает, какие именно документы должны стать регистраторами для уже существующих записей, она не может автоматически заполнить поле Регистратор. В результате старая таблица удаляется, а создается новая — пустая. Чтобы избежать потери данных, нам необходимо реализовать механизм временного хранения и последующего восстановления записей с явным указанием ссылок на регистраторы.
Разберем наиболее надежный способ, который минимизирует риск потери данных и позволяет отладить процесс переноса. Рассмотрим алгоритм действий:
ЦеныНоменклатуры в Удалить_ЦеныНоменклатуры).ЦеныНоменклатуры) и установим для него режим записи "Подчинение регистратору". Настроим состав измерений, ресурсов и реквизитов идентично старому регистру.Проанализируем пример кода для переноса данных из старого регистра в новый. Допустим, мы решили, что регистратором для старых записей станет специально созданный документ "Корректировка записей регистров":
// Пример переноса данных между регистрами
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| *
|ИЗ
| РегистрСведений.Удалить_ЦеныНоменклатуры КАК СтарыйРегистр";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь должна быть логика определения или создания Регистратора
ДокументСсылка = Документы.КорректировкаРегистров.НайтиПоРеквизиту("Комментарий", "Перенос данных");
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать(); // Читаем, чтобы дополнить набор, если регистратор один
НоваяЗапись = НаборЗаписей.Добавить();
ЗаполнитьЗначенияСвойств(НоваяЗапись, Выборка);
// Важный момент: установка активности
НоваяЗапись.Активность = Истина;
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();
КонецЦикла;
Преимущества данного метода: если в процессе переноса возникнет ошибка, данные в старом регистре останутся нетронутыми. После успешного переноса и проверки данных старый регистр можно будет удалить из конфигурации.
Если в регистре не слишком много записей (например, до 100-200 тысяч), мы можем использовать способ с сохранением данных в оперативную память. Рассмотрим этот процесс по шагам:
ТаблицаЗначений.ЗначениеВФайл или используя XML-сериализацию).Регистратор.Выясним причину, по которой стоит использовать ОбменДанными.Загрузка = Истина. При записи набора данных в подчиненный регистр могут срабатывать подписки на события или проверки в модуле набора записей. Установка этого флага позволяет обойти проверки (например, на закрытый период), что критично при восстановлении исторических данных.
Рассмотрим ситуацию, когда в регистре миллионы записей, и программный перенос через объекты 1С займет слишком много времени. В этом случае проанализируем возможность работы напрямую с СУБД (MS SQL или PostgreSQL). Внимание: данный метод не поддерживается фирмой 1С и может привести к неработоспособности базы, если не соблюдать осторожность.
Логика работы на уровне SQL выглядит следующим образом:
_Period, _RecorderTRef, _RecorderRRef, _LineNo и _Active.INSERT INTO ... SELECT переносим данные из временной таблицы в основную._RecorderRRef должно содержать GUID документа-регистратора в бинарном виде, а _LineNo — уникальный порядковый номер внутри каждого регистратора.Посмотрим на пример логики заполнения _LineNo средствами SQL. Можно использовать оконную функцию ROW_NUMBER() OVER(PARTITION BY ... ORDER BY ...), чтобы сформировать правильную нумерацию строк для каждого документа.
Проанализируем дополнительные параметры, которые появляются у подчиненного регистра и требуют обязательного заполнения:
Активность (в SQL — _Active) определяет, участвует ли запись в расчете итогов и отображается ли она в виртуальных таблицах (например, СрезПоследних). При переносе данных обязательно устанавливайте значение в Истина.НаборЗаписей, 1С заполнит их автоматически. Если же работаете напрямую через SQL, дублирование номеров строк приведет к ошибкам индексов.Подводя итог, можно сказать, что выбор метода зависит от объема данных и ваших навыков. Для большинства задач Метод 1 (Переименование) является оптимальным, так как он обеспечивает максимальную прозрачность и безопасность. Разберем еще раз ключевой совет: перед любыми манипуляциями с метаданными регистра, которые ведут к реструктуризации, всегда делайте резервную копию базы данных.
Если вы решили использовать существующие документы в качестве регистраторов, убедитесь, что в их модулях проведения прописаны движения по новому регистру, иначе при любом случайном перепроведении документов ваши восстановленные данные могут быть перезаписаны пустыми наборами.