При активном развитии конфигурации на платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с необходимостью изменения структуры метаданных. Одна из самых болезненных задач в распределенных информационных базах (УРБД) — это изменение подчиненности уже существующего справочника (например, когда ранее независимый справочник требуется сделать подчиненным другому объекту).
Если выполнять эту операцию стандартными средствами конфигуратора на заполненной базе данных, система выдаст ошибку реструктуризации: «Справочник имеет записи и не может быть подчинен». В распределенной базе ситуация осложняется тем, что изменения метаданных должны корректно и одновременно примениться как на центральной (ЦБ), так и на всех периферийных базах (ПБ) без потери данных и нарушения процесса автообмена.
Разберем подробно причины возникновения этой проблемы и рассмотрим два проверенных способа её решения: безопасный (архитектурный) и ручной (с техническим вмешательством в таблицы базы данных).
В архитектуре 1С 7.7 подчиненность справочника определяется наличием в его физической таблице специального системного поля PARENTEXT (длина — 9 символов, тип — Строка/Char). В этом поле хранится идентификатор (ID) элемента-владельца.
При попытке сделать справочник подчиненным конфигуратор пытается добавить колонку PARENTEXT в существующую таблицу базы данных с признаком NOT NULL. Поскольку в таблице уже есть данные, СУБД (как DBF-формат, так и MS SQL Server) отклоняет операцию добавления колонки NOT NULL без указания значения по умолчанию. Из-за этого процесс реструктуризации аварийно завершается.
---
Любое ручное редактирование таблиц базы данных в обход конфигуратора несет в себе риски нарушения ссылочной целостности и рассинхронизации УРБД. Поэтому наиболее надежным решением является перенос данных через создание нового справочника. Этот метод полностью автоматизирован и не требует ручного вмешательства на периферийных точках.
Проанализируем этот метод по шагам:
В центральной базе данных создаем новый справочник (например, НовыйСправочник). В его свойствах изначально указываем нужного владельца. Старый справочник при этом не трогаем и не удаляем.
Сохраняем конфигурацию в центральной базе и выполняем штатный обмен со всеми периферийными узлами. В результате обмена структура нового справочника без ошибок переносится на все периферийные базы.
Пишем внешнюю обработку (файлы формата .ert), которая будет выполняться только в центральной базе. Задача обработки — считать элементы из старого справочника, создать аналогичные элементы в новом справочнике с указанием владельца и заменить ссылки на старый справочник во всех документах, операциях и других реквизитах.
Рассмотрим пример кода для переноса элементов:
// Пример процедуры переноса элементов
Процедура ПеренестиДанные()
СпрСтарый = СоздатьОбъект("Справочник.СтарыйСправочник");
СпрНовый = СоздатьОбъект("Справочник.НовыйСправочник");
СпрСтарый.ВыбратьЭлементы();
Пока СпрСтарый.ПолучитьЭлемент() = 1 Цикл
// Алгоритм поиска или определения владельца для текущего элемента
СсылкаНаВладельца = ОпределитьВладельца(СпрСтарый.ТекущийЭлемент());
СпрНовый.Новый();
СпрНовый.ИспользоватьВладельца(СсылкаНаВладельца);
СпрНовый.Код = СпрСтарый.Код;
СпрНовый.Наименование = СпрСтарый.Наименование;
// Здесь заполняем остальные реквизиты, если они есть
СпрНовый.Записать();
// Заменяем ссылки на старый элемент во всей базе данных на новый элемент
ЗаменитьСсылки(СпрСтарый.ТекущийЭлемент(), СпрНовый.ТекущийЭлемент());
КонецЦикла;
КонецПроцедуры
Поскольку перенос данных и замена ссылок выполняются штатными программными методами 1С в центральной базе, система автоматически регистрирует изменения для всех измененных объектов (документов, нового справочника). При очередном обмене новые данные успешно мигрируют на все периферийные базы.
После того как данные на всех точках успешно перенесены, а обмены завершены, в центральной базе можно удалить старый справочник из метаданных и снова запустить штатное обновление конфигурации.
---
Если объем данных в справочнике слишком велик, а пересчет ссылок в документах займет слишком много времени, можно прибегнуть к ручной модификации структуры таблиц СУБД. Этот способ требует высокой квалификации администратора и четкого соблюдения последовательности действий.
Рассмотрим пошагово, как реализовать этот подход:
На копии центральной базы (или временно очистив справочник) изменяем подчиненность нужного справочника в конфигураторе. Сохраняем конфигурацию. Получаем обновленный файл конфигурации 1Cv7.MD и словарь данных 1Cv7.DD (или 1Cv7.DDS для SQL-версии).
При штатном обновлении конфигурации в центральной базе платформа автоматически регистрирует изменения метаданных для отправки на периферийные базы. Нам нужно предотвратить автоматическую отправку файла .md, так как структура таблиц на периферии еще не подготовлена. Для этого необходимо очистить таблицу регистрации изменений метаданных в центральной базе.
Нам необходимо вручную добавить системное поле PARENTEXT в таблицу нужного справочника на стороне периферийных баз (и на центральной, если процедура выполняется без очистки данных).
SC*.dbf). Добавляем новое поле PARENTEXT с типом Character (строка) и длиной 9. При создании поля временно разрешаем значения NULL (снимаем ограничение NOT NULL), чтобы СУБД позволила добавить колонку в заполненную таблицу.SC1234) и выполняем прямой SQL-запрос:
ALTER TABLE SC1234 ADD PARENTEXT char(9) NULL
После физического изменения структуры таблиц на периферийных базах заменяем в их каталогах файлы 1Cv7.MD и 1Cv7.DD (или 1Cv7.DDS) на новые файлы, полученные из центральной базы на Шаге 1.
Запускаем периферийные базы в монопольном режиме и с помощью внешней обработки заполняем поле владельца для каждого элемента справочника. Пример кода обработки:
// Пример заполнения владельца для существующего справочника
Процедура ЗаполнитьВладельцев()
Спр = СоздатьОбъект("Справочник.НужныйСправочник");
// Выбираем элементы без учета иерархии и подчинения
Спр.ВыбратьЭлементы(0);
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если ПустоеЗначение(Спр.Владелец) = 1 Тогда
СсылкаНаВладельца = ОпределитьВладельца(Спр.ТекущийЭлемент());
Спр.Владелец = СсылкаНаВладельца;
Спр.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
После ручной подмены конфигурационных файлов и заполнения владельцев необходимо обязательно запустить утилиту «Тестирование и исправление ИБ» в конфигураторе на каждой периферийной базе. Выбираем пункты «Проверка физической целостности» и «Реиндексация таблиц». Это нужно для того, чтобы СУБД корректно перестроила индексы таблиц с учетом нового поля PARENTEXT.
Важное предупреждение: Любое несовпадение физической структуры таблиц (даже на один байт в заголовке DBF-файла) между центральной и периферийной базами гарантированно приведет к критической ошибке при первом же сеансе автообмена УРБД. Поэтому первый способ (через создание нового справочника) всегда является более предпочтительным и безопасным для распределенных систем.