Восстановление данных из текстового файла — это классическая задача для начинающего разработчика 1С, которая позволяет глубоко изучить объектную модель платформы и работу с метаданными. В данной статье мы разберем ситуацию, когда информация о документе была выгружена в упрощенном текстовом формате вида ИмяРеквизита:Значение:Тип, и нам необходимо создать идентичный документ в базе данных, не используя при этом прямые ссылки или уникальные идентификаторы (GUID).
Основная сложность здесь заключается в том, что при чтении файла мы получаем обычные строки. Если для реквизитов типа Строка это не является проблемой, то для Справочников, Документов и Перечислений простого присваивания недостаточно — программа не сможет автоматически преобразовать текст "Основной склад" в ссылку на элемент справочника. Проанализируем, как решить эту задачу по шагам.
Прежде всего, нам необходимо создать новый документ нужного типа. Поскольку мы работаем в универсальном стиле, будем использовать коллекцию Документы и обращаться к ней по имени, полученному из файла или метаданных. Рассмотрим базовую структуру цикла загрузки:
НовыйДокумент = Документы[ИмяТипаДокумента].СоздатьДокумент();
// Устанавливаем дату и номер, если они есть в файле
НовыйДокумент.Дата = ДатаИзФайла;
НовыйДокумент.Номер = НомерИзФайла;
Для заполнения остальных полей мы будем обходить метаданные созданного документа. Это позволит нам точно знать, какой тип данных ожидает каждый конкретный реквизит. Выясним причину, по которой обычное присваивание НовыйДокумент[ИмяРеквизита] = ЗначениеИзФайла не работает: платформа ожидает объект типа СправочникСсылка, а получает Строка.
Для того чтобы найти ссылку в базе, нам нужно понять, в какой таблице искать. Если в файле тип указан как Справочник.Склады, нам необходимо разделить эту строку на две части: класс объекта (Справочник) и его имя (Склады). Проанализируем, как получить доступ к менеджеру объекта динамически:
// Пример разделения строки типа "Справочник.Склады"
МассивЧастей = СтрРазделить(ТипИзФайла, ".");
КлассОбъекта = МассивЧастей[0]; // Справочник
ИмяОбъекта = МассивЧастей[1]; // Склады
Если КлассОбъекта = "Справочник" Тогда
Менеджер = Справочники[ИмяОбъекта];
ИначеЕсли КлассОбъекта = "Документ" Тогда
Менеджер = Документы[ИмяОбъекта];
ИначеЕсли КлассОбъекта = "Перечисление" Тогда
Менеджер = Перечисления[ИмяОбъекта];
КонецЕсли;
Использование квадратных скобок Справочники[ИмяОбъекта] — это мощный инструмент 1С, позволяющий обращаться к любой коллекции метаданных по строковому имени. Это избавляет нас от необходимости писать громоздкие конструкции Если...Тогда для каждого конкретного справочника.
Теперь, когда у нас есть доступ к менеджеру, мы должны найти конкретный элемент. В условиях задачи запрещен поиск по УникальныйИдентификатор, поэтому рассмотрим альтернативные методы поиска: по наименованию или по коду.
Поиск по наименованию: Самый простой, но рискованный метод, так как в базе могут быть элементы с одинаковыми названиями.
НайденнаяСсылка = Менеджер.НайтиПоНаименованию(ЗначениеИзФайла, Истина);
Если НайденнаяСсылка.Пустая() Тогда
Сообщить("Элемент не найден: " + ЗначениеИзФайла);
КонецЕсли;
Поиск по коду: Более надежный метод для справочников. Если при выгрузке вы сохраняли код элемента, используйте Менеджер.НайтиПоКоду(КодИзФайла). Для документов поиск обычно осуществляется по связке Дата + Номер, так как номера могут дублироваться в разных годах.
Перечисления в 1С стоят особняком. У них нет методов НайтиПоНаименованию или НайтиПоКоду. Ссылка на значение перечисления получается путем прямого обращения к менеджеру по имени значения, которое было задано в конфигураторе. Посмотрим на пример:
// ЗначениеИзФайла должно содержать имя значения, например "Опт" или "Розница"
Попытка
НовыйДокумент[ИмяРеквизита] = Перечисления[ИмяОбъекта][ЗначениеИзФайла];
Исключение
Сообщить("Не удалось определить значение перечисления для " + ИмяРеквизита);
КонецПопытки;
Если в файл выгружен "Синоним" (то, что видит пользователь), а не "Имя", вам придется перебирать все значения перечисления в цикле через Метаданные.Перечисления[ИмяОбъекта].ЗначенияПеречисления и сравнивать их синонимы с текстом из файла.
Не забудем про примитивные типы данных. При чтении из текстового файла всё является строкой, поэтому нам нужно выполнить явное приведение типов. Разберем, как это сделать правильно:
Число(ЗначениеИзФайла). Важно убедиться, что разделитель дробной части в файле совпадает с локальными настройками системы (обычно запятая или точка).ГГГГММДДччммсс. Тогда преобразование выполняется функцией Дата(ЗначениеИзФайла).НовыйДокумент[ИмяРеквизита] = (ЗначениеИзФайла = "Истина").Документ редко состоит только из шапки. Нам нужно восстановить и табличные части. В текстовом файле строки ТЧ обычно помечаются специальным префиксом или хранятся в отдельном блоке. Разберем алгоритм заполнения:
// Предположим, мы определили, что текущая строка файла относится к ТЧ "Товары"
НоваяСтрока = НовыйДокумент.Товары.Добавить();
// Далее заполняем реквизиты строки так же, как реквизиты шапки
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию(ЗначениеИзФайла);
НоваяСтрока.Количество = Число(КоличествоИзФайла);
Важный момент: При работе с составными типами данных (когда реквизит может быть и Справочником, и Документом) обязательно анализируйте тип, указанный в файле, чтобы выбрать правильный менеджер для поиска.
Мы проанализировали процесс восстановления документа и выяснили, что ключ к успеху лежит в грамотном использовании коллекции метаданных и динамическом обращении к менеджерам объектов. Посмотрим на основные выводы:
Пустая(). Если объект не найден, документ может записаться с пустым полем, что приведет к ошибкам в учете.ТипЗнч() и метод метаданных НайтиПоТипу(), чтобы понимать, какой объект перед вами.Спроектированный таким образом алгоритм является универсальным. Его можно использовать не только для восстановления одного документа, но и для создания полноценной системы обмена данными между разнородными базами 1С через текстовые файлы.