Как восстановить двоичные данные файлов в 1С из архива, если тип ресурса изменился на строку

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

Ситуация, когда после неудачного обновления конфигурации или динамического обновления тип ресурса в регистре сведений (например, ДвоичныеДанныеФайлов) самопроизвольно меняется с типа ХранилищеЗначения (двоичные данные) на тип Строка, является критической. В этом случае все существующие файлы «отваливаются», а новые данные записываются некорректно. Разберем по шагам, как оптимально вернуть данные из архивной копии в рабочую базу, сохранив при этом новые записи, появившиеся после сбоя.

Анализ проблемы и подготовка инструментов

Проанализируем ситуацию: при смене типа данных на уровне СУБД 1С пересоздает колонку в таблице. Если тип изменился на строку, то бинарные данные (BLOB) могли быть либо обрезаны, либо необратимо конвертированы в текстовый формат в зависимости от настроек SQL-сервера. Простое изменение типа обратно на ХранилищеЗначения в конфигураторе не вернет содержимое файлов — колонки будут либо пустыми, либо содержать «мусор».

Для восстановления нам потребуется:

  1. Архивная копия базы данных (SQL-бэкап или выгрузка .dt), созданная до момента злополучного обновления.
  2. Доступ к консоли управления MS SQL Server (если база клиент-серверная) или навыки написания внешних обработок 1С.
  3. Имя таблицы регистра в операционной базе и в архиве.

Рассмотрим, как найти имя таблицы. В 1С таблицы регистров сведений именуются как _InfoRg с порядковым номером. Чтобы узнать точное имя, выполним в рабочей базе следующий код:


ИмяТаблицы = ПолучитьСтруктуруХраненияБазыДанных("РегистрСведений.ДвоичныеДанныеФайлов", Истина).ИмяТаблицыХранения;
Сообщить(ИмяТаблицы); // Например, вернет _InfoRg1234

Метод 1: Прямое восстановление через SQL-запрос (самый быстрый способ)

Если рабочая база и восстановленный архив находятся на одном SQL-сервере, мы можем выполнить операцию UPDATE с соединением таблиц (Cross-Database Join). Это позволит мгновенно перелить данные без долгой выгрузки-загрузки.

Разберем алгоритм действий:

  1. Развернем архивную копию базы на том же SQL-сервере под именем Base_Archive.
  2. Определим имена таблиц регистра в обеих базах (они могут отличаться, например _InfoRg1234 в рабочей и _InfoRg5678 в архиве).
  3. Выполним SQL-запрос, который сопоставит записи по измерениям (обычно это ссылка на файл) и обновит ресурс с данными.

Пример SQL-запроса для восстановления:


UPDATE WorkDB.dbo._InfoRg1234
SET _Fld1235 = ArchiveDB.dbo._InfoRg5678._Fld5679
FROM WorkDB.dbo._InfoRg1234 AS WorkDB
INNER JOIN ArchiveDB.dbo._InfoRg5678 AS ArchiveDB
ON WorkDB._Fld1230_RRRef = ArchiveDB._Fld5675_RRRef -- Сопоставление по ссылке на файл
WHERE (WorkDB._Fld1235 IS NULL OR DATALENGTH(WorkDB._Fld1235) < 100) -- Условие для обновления только пустых/битых данных

Важно: Перед выполнением подобных запросов обязательно сделайте свежий бэкап рабочей базы! После выполнения запроса необходимо выполнить реиндексацию таблиц через «Тестирование и исправление» в конфигураторе 1С.

Метод 2: Использование механизма «Внешние источники данных»

Если вы не хотите работать напрямую с SQL или базы находятся на разных серверах, воспользуемся стандартным механизмом 1С — ВнешниеИсточникиДанных. Этот способ надежнее, так как 1С сама контролирует типы данных при записи.

Рассмотрим шаги реализации:

  1. В рабочей конфигурации временно добавим новый ВнешнийИсточникДанных.
  2. Настроим строку подключения к архивной базе SQL.
  3. Добавим таблицу регистра _InfoRgXXXX из архива в состав внешнего источника.
  4. Напишем небольшую обработку, которая в цикле прочитает данные из внешнего источника и запишет их в основной регистр 1С.

Пример кода обработки:


&НаСервере
Процедура ВосстановитьДанныеФайлов()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Архив.ФайлСсылка КАК Файл,
        |   Архив.ДвоичныеДанные КАК Данные
        |ИЗ
        |   ВнешнийИсточникДанных.АрхивнаяБаза.Таблица.dbo_InfoRg5678 КАК Архив";
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        МенеджерЗаписи = РегистрыСведений.ДвоичныеДанныеФайлов.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.Файл = Выборка.Файл;
        МенеджерЗаписи.Прочитать();
        
        Если МенеджерЗаписи.Выбран() Тогда
            // Записываем данные, только если они пустые или не соответствуют типу
            Если ТипЗнч(МенеджерЗаписи.ДвоичныеДанныеФайла) <> Тип("ХранилищеЗначения") Тогда
                МенеджерЗаписи.ДвоичныеДанныеФайла = Выборка.Данные; // Предполагается, что в источнике это BLOB
                МенеджерЗаписи.Записать();
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Метод 3: Использование COM-соединения (если объем данных небольшой)

Проанализируем ситуацию, когда данных немного и нужно быстро «на коленке» написать перенос. Мы можем подключиться из рабочей базы к архиву (файловому или серверному) через COMConnector.

Выясним причину выбора этого метода: он не требует прав администратора SQL и изменения структуры конфигурации. Однако он работает медленнее остальных.

Пример алгоритма на 1С:


ПутьКБазе = "Srvr=""ServerName"";Ref=""ArchiveBaseName"";";
COM = Новый COMОбъект("V83.COMConnector");
Соединение = COM.Connect(ПутьКБазе + "Usr=""Admin"";Pwd=""123"";");

РегистрАрхив = Соединение.РегистрыСведений.ДвоичныеДанныеФайлов;
ВыборкаАрхив = РегистрАрхив.Выбрать();

Пока ВыборкаАрхив.Следующий() Цикл
    // Ищем соответствующую запись в текущей базе
    Менеджер = РегистрыСведений.ДвоичныеДанныеФайлов.СоздатьМенеджерЗаписи();
    Менеджер.Файл = ПоискСсылкиВТекущейБазе(ВыборкаАрхив.Файл); // Нужно сопоставить GUID
    Менеджер.Прочитать();
    
    Если Менеджер.Выбран() Тогда
        // Получаем двоичные данные через временный файл или напрямую, если COM позволяет
        ДвоичныеДанные = ВыборкаАрхив.ДвоичныеДанныеФайла.Получить();
        Менеджер.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
        Менеджер.Записать();
    КонецЕсли;
КонецЦикла;

Инкрементальное восстановление и обработка новых данных

Посмотрим на важный нюанс: в рабочей базе уже появились новые файлы, созданные после сбоя. При их записи 1С пыталась запихнуть бинарные данные в поле типа Строка. Эти данные, скорее всего, безвозвратно испорчены.

Рекомендуем следующий подход при восстановлении:

Завершающие операции: реиндексация и кэш

После того как мы восстановили данные в таблицах SQL, 1С может продолжать «видеть» старые строковые значения из-за кэширования или некорректных индексов. Проанализируем обязательные шаги после восстановления:

  1. Тестирование и исправление: Обязательно запустите «Реиндексацию таблиц» и «Пересчет итогов». Это заставит СУБД обновить внутренние указатели на новые BLOB-данные.
  2. Очистка серверного кэша: Остановите службу агента 1С и удалите содержимое папки srvinfo (за исключением файлов конфигурации и журналов), чтобы исключить ошибки «Несоответствие типов» при обращении к регистру.
  3. Проверка справочника «Файлы»: Убедитесь, что реквизиты Размер и Расширение в справочнике Файлы соответствуют восстановленным данным в регистре. Если они разошлись, функции печати и просмотра могут выдавать ошибку.

Таким образом, наиболее эффективным и быстрым способом является прямой SQL UPDATE, если вы уверенно владеете инструментами СУБД. Для более безопасного, но медленного переноса лучше использовать Внешние источники данных, которые позволяют работать с архивом как с родной таблицей 1С.

← На главную