Ситуация, когда после неудачного обновления конфигурации или динамического обновления тип ресурса в регистре сведений (например, ДвоичныеДанныеФайлов) самопроизвольно меняется с типа ХранилищеЗначения (двоичные данные) на тип Строка, является критической. В этом случае все существующие файлы «отваливаются», а новые данные записываются некорректно. Разберем по шагам, как оптимально вернуть данные из архивной копии в рабочую базу, сохранив при этом новые записи, появившиеся после сбоя.
Проанализируем ситуацию: при смене типа данных на уровне СУБД 1С пересоздает колонку в таблице. Если тип изменился на строку, то бинарные данные (BLOB) могли быть либо обрезаны, либо необратимо конвертированы в текстовый формат в зависимости от настроек SQL-сервера. Простое изменение типа обратно на ХранилищеЗначения в конфигураторе не вернет содержимое файлов — колонки будут либо пустыми, либо содержать «мусор».
Для восстановления нам потребуется:
Рассмотрим, как найти имя таблицы. В 1С таблицы регистров сведений именуются как _InfoRg с порядковым номером. Чтобы узнать точное имя, выполним в рабочей базе следующий код:
ИмяТаблицы = ПолучитьСтруктуруХраненияБазыДанных("РегистрСведений.ДвоичныеДанныеФайлов", Истина).ИмяТаблицыХранения;
Сообщить(ИмяТаблицы); // Например, вернет _InfoRg1234
Если рабочая база и восстановленный архив находятся на одном SQL-сервере, мы можем выполнить операцию UPDATE с соединением таблиц (Cross-Database Join). Это позволит мгновенно перелить данные без долгой выгрузки-загрузки.
Разберем алгоритм действий:
Base_Archive._InfoRg1234 в рабочей и _InfoRg5678 в архиве).Пример 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С.
Если вы не хотите работать напрямую с SQL или базы находятся на разных серверах, воспользуемся стандартным механизмом 1С — ВнешниеИсточникиДанных. Этот способ надежнее, так как 1С сама контролирует типы данных при записи.
Рассмотрим шаги реализации:
ВнешнийИсточникДанных._InfoRgXXXX из архива в состав внешнего источника.Пример кода обработки:
&НаСервере
Процедура ВосстановитьДанныеФайлов()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Архив.ФайлСсылка КАК Файл,
| Архив.ДвоичныеДанные КАК Данные
|ИЗ
| ВнешнийИсточникДанных.АрхивнаяБаза.Таблица.dbo_InfoRg5678 КАК Архив";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
МенеджерЗаписи = РегистрыСведений.ДвоичныеДанныеФайлов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Файл = Выборка.Файл;
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
// Записываем данные, только если они пустые или не соответствуют типу
Если ТипЗнч(МенеджерЗаписи.ДвоичныеДанныеФайла) <> Тип("ХранилищеЗначения") Тогда
МенеджерЗаписи.ДвоичныеДанныеФайла = Выборка.Данные; // Предполагается, что в источнике это BLOB
МенеджерЗаписи.Записать();
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем ситуацию, когда данных немного и нужно быстро «на коленке» написать перенос. Мы можем подключиться из рабочей базы к архиву (файловому или серверному) через COMConnector.
Выясним причину выбора этого метода: он не требует прав администратора SQL и изменения структуры конфигурации. Однако он работает медленнее остальных.
Пример алгоритма на 1С:
ПутьКБазе = "Srvr=""ServerName"";Ref=""ArchiveBaseName"";";
COM = Новый COMОбъект("V83.COMConnector");
Соединение = COM.Connect(ПутьКБазе + "Usr=""Admin"";Pwd=""123"";");
РегистрАрхив = Соединение.РегистрыСведений.ДвоичныеДанныеФайлов;
ВыборкаАрхив = РегистрАрхив.Выбрать();
Пока ВыборкаАрхив.Следующий() Цикл
// Ищем соответствующую запись в текущей базе
Менеджер = РегистрыСведений.ДвоичныеДанныеФайлов.СоздатьМенеджерЗаписи();
Менеджер.Файл = ПоискСсылкиВТекущейБазе(ВыборкаАрхив.Файл); // Нужно сопоставить GUID
Менеджер.Прочитать();
Если Менеджер.Выбран() Тогда
// Получаем двоичные данные через временный файл или напрямую, если COM позволяет
ДвоичныеДанные = ВыборкаАрхив.ДвоичныеДанныеФайла.Получить();
Менеджер.ДвоичныеДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные);
Менеджер.Записать();
КонецЕсли;
КонецЦикла;
Посмотрим на важный нюанс: в рабочей базе уже появились новые файлы, созданные после сбоя. При их записи 1С пыталась запихнуть бинарные данные в поле типа Строка. Эти данные, скорее всего, безвозвратно испорчены.
Рекомендуем следующий подход при восстановлении:
ДвоичныеДанныеФайлов записи, созданные в период между «падением» и текущим моментом, если их невозможно восстановить.После того как мы восстановили данные в таблицах SQL, 1С может продолжать «видеть» старые строковые значения из-за кэширования или некорректных индексов. Проанализируем обязательные шаги после восстановления:
srvinfo (за исключением файлов конфигурации и журналов), чтобы исключить ошибки «Несоответствие типов» при обращении к регистру.Размер и Расширение в справочнике Файлы соответствуют восстановленным данным в регистре. Если они разошлись, функции печати и просмотра могут выдавать ошибку.Таким образом, наиболее эффективным и быстрым способом является прямой SQL UPDATE, если вы уверенно владеете инструментами СУБД. Для более безопасного, но медленного переноса лучше использовать Внешние источники данных, которые позволяют работать с архивом как с родной таблицей 1С.