При переносе данных из устаревших версий «1С:Предприятия 7.7» в современную платформу «1С:Предприятие 8» разработчики часто сталкиваются с ситуацией, когда прямое подключение через COM-соединение (V77.Application) невозможно или нецелесообразно. Причинами могут быть разрядность серверов (x64), повреждение OLE-компонентов, отсутствие установленной платформы 7.7 на целевом сервере или требование работать напрямую с резервными копиями таблиц DBF.
В такой ситуации возникает задача прямого чтения таблиц баз данных 7.7. Разберем подробно, как устроена структура хранения данных в таблицах 1С 7.7, где искать соответствие таблиц и реквизитов, как закодированы ссылки на родительские группы и какими способами можно перенести иерархию справочника (например, «Номенклатура») в 1С 8.
Проанализируем организацию файлов базы данных формата DBF в 1С 7.7. В отличие от конфигураций на платформе 1С 8, где имена физических таблиц в СУБД формируются по внутренним идентификаторам метаданных, в 1С 7.7 вся карта соответствия объектов базы хранится в специальном текстовом файле словаря данных — 1Cv7.DD (Data Dictionary), расположенном в корне каталога информационной базы.
Каждому справочнику конфигурации соответствует отдельный файл с именем вида SC***.DBF, где *** — уникальный числовой идентификатор объекта. Открыв файл 1Cv7.DD в любом текстовом редакторе, найдем секцию нужного справочника. Например, для справочника «Номенклатура» описание будет выглядеть следующим образом:
#===============================================================================
#==ТАБЛИЦА : Справочник Номенклатура
#==ИМЯ : SC84
#===============================================================================
Fields:
Field 1 : ID : Char(9) : Идентификатор объекта
Field 2 : PARENTID : Char(9) : Идентификатор родителя
Field 3 : CODE : Char(10) : Код
Field 4 : DESCR : Char(100) : Наименование
Field 5 : ISFOLDER : Numeric(1): ЭтоГруппа (1 - папка, 2 - элемент)
Field 6 : ISMARK : Logical : ПометкаУдаления
Рассмотрим ключевые служебные поля, отвечающие за построение иерархии:
ID — уникальный идентификатор записи в таблице. Имеет тип Char(9) и представляет собой девятисимвольную строку в 36-ричной системе счисления (символы 0–9 и A–Z). Первые 6 символов кодируют порядковый номер записи, а последние 3 символа содержат код узла информационной базы (префикс распределенной ИБ).PARENTID — идентификатор родительской группы. Поле присутствует во всех справочниках с количеством уровней иерархии больше одного. Если элемент или группа находится в корне справочника (не имеет родителя), в поле PARENTID записывается пустой идентификатор: " 0 " (пять пробелов, ноль, три пробела).ISFOLDER — признак типа записи. Принимает числовое значение: 1 — запись является группой (папкой), 2 — запись является конечным элементом.ISMARK — признак пометки на удаление (логическое поле T / F или символ *).Прежде чем приступать к загрузке данных в 1С 8, обратим внимание на важные технические нюансы:
XBase в платформе 1С 8 обязательно проверяем и задаем правильную кодировку, иначе все строковые реквизиты (наименования, артикулы) загрузятся с искажениями.SC***.DBF хранятся только непериодические реквизиты. Все периодические значения (например, цены, базовые единицы или периодические реквизиты) хранятся в общей таблице 1SCONST.DBF и связываются по условию OBJID = SC***.ID.SC***.DBT либо в системную таблицу 1STRCNT.DBF.Разберем наиболее надежный и простой в отладке алгоритм переноса иерархии. Проблема прямой последовательной загрузки из DBF заключается в том, что в файле дочерние элементы могут физически располагаться раньше, чем их группы-родители. Если попытаться сразу проставить родителя, нужного объекта в базе 1С 8 еще может не существовать.
Для решения этой задачи выполним загрузку в два этапа:
SC***.DBF, создаем все группы и элементы в 1С 8 (группы создаем через Справочники.Номенклатура.СоздатьГруппу(), элементы — через Справочники.Номенклатура.СоздатьЭлемент()). Заполняем код, наименование и прочие базовые реквизиты, но поле Родитель оставляем пустым. В объекте Соответствие сохраняем связь: ключ — строковый ID из 7.7, значение — полученная Ссылка нового объекта 1С 8.PARENTID не равно пустому значению " 0 ", находим ссылку родителя в нашем объекте Соответствие и записываем реквизит Родитель у созданного объекта.Посмотрим на программную реализацию данного способа на встроенном языке 1С:Предприятия 8:
Процедура ЗагрузитьНоменклатуруИзDBF_ДваПрохода(ПутьКФайлуDBF) Экспорт
ФайлDBF = Новый XBase;
ФайлDBF.Кодировка = КодировкаXBase.КодировкаDOS; // При необходимости меняем на КодировкаWindows
ФайлDBF.ОткрытьФайл(ПутьКФайлуDBF);
Если Не ФайлDBF.Открыта() Тогда
ВызватьИсключение "Не удалось открыть файл таблицы 1С 7.7: " + ПутьКФайлуDBF;
КонецЕсли;
ТаблицаСсылок = Новый Соответствие; // Ключ - ID_77, Значение - Ссылка_8
// --- Первый проход: создание всех групп и элементов ---
ФайлDBF.Первая();
Пока Не ФайлDBF.ВКонце() Цикл
Идентификатор77 = СокрЛП(ФайлDBF.ID);
ЭтоПапка = (ФайлDBF.ISFOLDER = 1);
Наименование = СокрЛП(ФайлDBF.DESCR);
КодЭлемента = СокрЛП(ФайлDBF.CODE);
ПометкаУдаления = (ФайлDBF.ISMARK = Истина);
Если ЭтоПапка Тогда
НовыйОбъект = Справочники.Номенклатура.СоздатьГруппу();
Иначе
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
КонецЕсли;
НовыйОбъект.Наименование = Наименование;
НовыйОбъект.Код = КодЭлемента;
НовыйОбъект.ПометкаУдаления = ПометкаУдаления;
// Дополнительно можно заполнить артикул, единицу и другие реквизиты
Попытка
НовыйОбъект.Записать();
ТаблицаСсылок.Вставить(Идентификатор77, НовыйОбъект.Ссылка);
Исключение
Сообщить("Ошибка при создании объекта: " + Наименование + " (" + ОписаниеОшибки() + ")");
КонецПопытки;
ФайлDBF.Следующая();
КонецЦикла;
// --- Второй проход: расстановка связей иерархии ---
ФайлDBF.Первая();
Пока Не ФайлDBF.ВКонце() Цикл
Идентификатор77 = СокрЛП(ФайлDBF.ID);
РодительID77 = СокрЛП(ФайлDBF.PARENTID);
// Проверяем, есть ли родитель (в 7.7 корень обозначается как "0" или пустая строка с пробелами)
Если РодительID77 <> "0" И ЗначениеЗаполнено(РодительID77) Тогда
СсылкаНаОбъект = ТаблицаСсылок.Получить(Идентификатор77);
СсылкаНаРодителя = ТаблицаСсылок.Получить(РодительID77);
Если СсылкаНаОбъект <> Неопределено И СсылкаНаРодителя <> Неопределено Тогда
ОбъектДляИзменения = СсылкаНаОбъект.ПолучитьОбъект();
Если ОбъектДляИзменения.Родитель <> СсылкаНаРодителя Тогда
ОбъектДляИзменения.Родитель = СсылкаНаРодителя;
Попытка
ОбъектДляИзменения.Записать();
Исключение
Сообщить("Не удалось установить родителя для: " + СсылкаНаОбъект);
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ФайлDBF.Следующая();
КонецЦикла;
ФайлDBF.ЗакрытьФайл();
Сообщить("Импорт номенклатуры с иерархией успешно завершен!");
КонецПроцедуры
Рассмотрим более продвинутый подход, который платформа 1С 8 позволяет реализовать благодаря механизму ПолучитьСсылку() по предопределенному объекту УникальныйИдентификатор.
Смысл метода заключается в том, что мы можем сформировать ссылку на объект еще до его физической записи в базу данных. Преобразуем строковый ID из 7.7 в корректный UUID (например, дополнив строку фиксированными нулями до 32 шестнадцатеричных символов или вычислив детерминированный хэш MD5). В результате при считывании строки файла мы сразу знаем как будущую ссылку самого элемента, так и готовую ссылку его родителя.
Посмотрим на пример генерации фиксированного идентификатора и создания объектов за один проход:
Функция ПолучитьUUID_Из_ID77(ID77)
// ID77 содержит 9 символов. Дополним строку нулями до стандартного GUID формата 8-4-4-4-12
СтрокаХэша = "00000000-0000-0000-0000-" + Прав("000000000000" + ВРег(СокрЛП(ID77)), 12);
Возврат Новый УникальныйИдентификатор(СтрокаХэша);
КонецФункции
Процедура ЗагрузитьНоменклатуруИзDBF_ОдинПроход(ПутьКФайлуDBF) Экспорт
ФайлDBF = Новый XBase;
ФайлDBF.Кодировка = КодировкаXBase.КодировкаDOS;
ФайлDBF.ОткрытьФайл(ПутьКФайлуDBF);
Если Не ФайлDBF.Открыта() Тогда
Возврат;
КонецЕсли;
ФайлDBF.Первая();
Пока Не ФайлDBF.ВКонце() Цикл
Идентификатор77 = СокрЛП(ФайлDBF.ID);
РодительID77 = СокрЛП(ФайлDBF.PARENTID);
ЭтоПапка = (ФайлDBF.ISFOLDER = 1);
// Получаем заранее вычисленную ссылку для текущего элемента
ГУИД_Элемента = ПолучитьUUID_Из_ID77(Идентификатор77);
СсылкаНаОбъект = Справочники.Номенклатура.ПолучитьСсылку(ГУИД_Элемента);
Если ЭтоПапка Тогда
НовыйОбъект = Справочники.Номенклатура.СоздатьГруппу();
Иначе
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
КонецЕсли;
// Устанавливаем предопределенную ссылку
НовыйОбъект.УстановитьСсылкуНового(СсылкаНаОбъект);
НовыйОбъект.Наименование = СокрЛП(ФайлDBF.DESCR);
НовыйОбъект.Код = СокрЛП(ФайлDBF.CODE);
НовыйОбъект.ПометкаУдаления = (ФайлDBF.ISMARK = Истина);
// Если есть родитель, сразу формируем на него ссылку
Если РодительID77 <> "0" И ЗначениеЗаполнено(РодительID77) Тогда
ГУИД_Родителя = ПолучитьUUID_Из_ID77(РодительID77);
НовыйОбъект.Родитель = Справочники.Номенклатура.ПолучитьСсылку(ГУИД_Родителя);
КонецЕсли;
Попытка
НовыйОбъект.Записать();
Исключение
Сообщить("Ошибка записи объекта: " + ОписаниеОшибки());
КонецПопытки;
ФайлDBF.Следующая();
КонецЦикла;
ФайлDBF.ЗакрытьФайл();
КонецПроцедуры
Если разбор структуры файлов 1Cv7.DD кажется избыточным или требуется перенести сложные периодические реквизиты и подчиненные справочники, проанализируем типовые альтернативы:
V77Exp.ert, настраиваются правила обмена (ПКО, ПКС), и формируется стандартный XML-файл. На стороне 1С 8 файл читается обработкой УниверсальныйОбменДаннымиXML.epf. Этот метод автоматически обрабатывает иерархию любой глубины и не требует использования COM-соединения.ВыбратьЭлементы() и выгрузить плоскую таблицу с полями ИД, ИД_Родителя, ЭтоГруппа, Код, Наименование. Это избавит от необходимости сопоставлять имена файлов таблиц через 1Cv7.DD.Таким образом, понимание назначения полей PARENTID, ISFOLDER и формата идентификаторов 1С 7.7 позволяет быстро и корректно перенести любую сложную иерархическую структуру в 1С 8, используя стандартный объект XBase встроенного языка.