Периодически возникает необходимость выполнить частичное восстановление данных. Восстановить ИБ из резервной копии нельзя, как и допустить потери других изменений.
Описание ситуации
Например в рабочей ИБ в справочнике Номенклатура, пользователи в части элементов откорректировали значение реквизита Артикул, но изменения эти не корректны.
В рабочей ИБ элементы справочника Номенклатура выглядят так:
Восстановить ИБ из резервной копии нельзя, как и выполнить загрузку элементов справочника Номенклатура из копии ИБ обработкой ВыгрузкаЗагрузкаДанныхXML т.к. изменения обнаружены не сразу, а потери других изменений допускать нельзя.
В копии ИБ элементы справочника Номенклатура выглядят так:
Решение
В данной ситуации могут помочь два метода глобального контекста ЗначениеВФайл() и ЗначениеИзфайла(). Первый из них выполняет сохранение любых сериализуемых значений в файл, а второй восстанавливает из файла.
Прелесть в том, что ссылка является сериализуемой и никаких дополнительных манипуляции для сохранения и восстановления не потребуется.
По сути необходимо написать обработку, которая в копии ИБ сформирует коллекцию ссылок справочника Номенклатура со значениями реквизита Артикула и сохранит получившееся в файл. После эта же обработка в ИБ, восстановит заполненные данные из файла и выполнит запись правильных значений реквизита Артикул в справочнике Номенклатура.
Создадим новую обработку и назовем ее ЧастичноеВосстановлениеДанныхИзКопииИБ.
Сбор данных
В обработке создаем табличную часть Товары, в нее добавим реквизиты:
- Номенклатура. тип СправочникСсылка.Номенклатура;
- Артикул. тип Строка(15). Исходя из типа одноименного реквизита справочника Номенклатура.
Создаем форму обработки, на форму добавляем табличную часть Товары и ее реквизиты. Дополнительно в таблицу формы вытащим подчиненный реквизит Артикул из реквизита Номенклатура и установим ему синоним Номенклатура.Артикул. Это необходимо для вывода значения реквизита Артикул из элемента справочника Номенклатура в текущей ИБ.
В форме добавляем команду ЗаполнитьДанные, создаем ее обработчик, в котором заполняем табличную часть Товары исключив элементы с признаком ЭтоГруппа. Не забудь перенести команду на форму)
&НаКлиенте Процедура ЗаполнитьДанные(Команда) ЗаполнитьДанныеНаСервере(); КонецПроцедуры &НаСервере Процедура ЗаполнитьДанныеНаСервере() Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Номенклатура.Ссылка КАК Номенклатура, | Номенклатура.Артикул КАК Артикул |ИЗ | Справочник.Номенклатура КАК Номенклатура |ГДЕ | НЕ Номенклатура.ЭтоГруппа"; Объект.Товары.Загрузить(Запрос.Выполнить().Выгрузить()); КонецПроцедуры
При выполнении команды табличная часть будет заполнена
Сохранение данных в файл
Теперь необходимо полученные данные сохранить в файл. Для этого создаем серверную функцию СохранитьДанныеВФайлНаСервере(), которая будет помещать файл с нашими данными во временное хранилище и возвращать его адрес.
Описываем сохранение данных в файл методом ЗначениеВФайл(), затем помещаем файл во временное хранилище и адрес временного хранилища будет результатом работы функции.
&НаСервере Функция СохранитьДанныеВФайлНаСервере() ИмяФайла = ПолучитьИмяВременногоФайла(); ЗначениеВФайл(ИмяФайла, Объект.Товары.Выгрузить()); Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайла)); Возврат Адрес; КонецФункции
На форме добавляем команду СохранитьДанныеВФайл, создаем ее клиентский обработчик.
Получаем адрес временного хранилища с данными файла нашей выгрузки из функции СохранитьДанныеВФайлНаСервере(). Затем получим файл из временного хранилища при помощи метода НачатьПолучениеФайлаССервера().
&НаКлиенте Процедура СохранитьДанныеВФайл(Команда) Адрес = СохранитьДанныеВФайлНаСервере(); ПараметрыДиалога = Новый ПараметрыДиалогаПолученияФайлов; ПараметрыДиалога.Заголовок = "Сохранение выгружаемых данных"; ПараметрыДиалога.ВыборКаталога = Ложь; НачатьПолучениеФайлаССервера(Адрес, "Выгруженные данные.tmp", ПараметрыДиалога); КонецПроцедуры
При выполнении команды появится диалог с предложением сохранить или открыть полученный файл.
Выбираем сохранение и в появившемся системном диалоге сохранения файла указываем путь сохранения.
Разработка функционала для ИБ-донора завершена, переходим к функционалу для рабочей ИБ.
Загрузка данных из файла
Создадим команду ЗагрузитьДанныеИзФайла, в обработчике опишем диалог выбора файла и описание оповещения, которые передадим в метод НачатьПомещениеФайла().
&НаКлиенте Процедура ЗагрузитьДанныеИзФайла(Команда) Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие); Диалог.Фильтр = "(*.tmp)|*.tmp"; Диалог.ПроверятьСуществованиеФайла = Истина; Диалог.МножественныйВыбор = Ложь; Оповещение = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтаФорма); НачатьПомещениеФайла(Оповещение, , Диалог, Истина, УникальныйИдентификатор); КонецПроцедуры
После выбора файла вызовется процедура указанная в описании оповещения, в которой необходимо обработать результат. Просто проверим выбран ли файл, и если все в порядке, то вызовем процедуру загрузки данных в ТЧ с передачей в нее адреса временного хранилища выбранного файла.
&НаКлиенте Процедура ПослеВыбораФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт Если Не Результат Тогда Возврат; КонецЕсли; ВосстановитьДанныеИзФайлаНаСервере(Адрес); КонецПроцедуры
Теперь опишем процедуру получения файла из временного хранилища, получение данных из файла методом ЗначениеИзФайла() и загрузку их в ТЧ.
&НаСервере Процедура ВосстановитьДанныеИзФайлаНаСервере(Адрес) ИмяФайла = ПолучитьИмяВременногоФайла(); ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес); ДвоичныеДанные.Записать(ИмяФайла); Объект.Товары.Загрузить(ЗначениеИзФайла(ИмяФайла)); КонецПроцедуры
При выполнении команды табличная часть будет заполнена
Если интересна информация по теме «Объект не найден«, то разбирал вариант поиска в статье 1C. Поиск «Объект не найден» в регистре и удаление.
Запись данных
Остается написать процедуру для записи восстановленных в ТЧ. Обойдем ТЧ получая объект номенклатуры, и при необходимости будем восстанавливать артикул и записывать объект.
С большой вероятностью, есть элементы артикул в которых не изменился, такие элементы перезаписывать не будем.
Так же возможна ситуация, когда в ИБ удалили номенклатуру, которая есть в файле. Учтем и ее проверив на заполненность наименование объекта, наименование обязательно к заполнению.
&НаСервере Процедура ЗаписатьДанныеНаСервере() Для Каждого СтрокаТовары Из Объект.Товары Цикл НоменклатураОбъект = СтрокаТовары.Номенклатура.ПолучитьОбъект(); Если НоменклатураОбъект = Неопределено Тогда Продолжить; // Пропустим удаленные объекты КонецЕсли; Если НоменклатураОбъект.Артикул = СтрокаТовары.Артикул Тогда Продолжить; // Пропускаем не измененные артикулы КонецЕсли; НоменклатураОбъект.Артикул = СтрокаТовары.Артикул; НоменклатураОбъект.ОбменДанными.Загрузка = Истина; Попытка НоменклатураОбъект.Записать(); Исключение ТекстСообщения = СтрШаблон("Не удалось записать элемент %1. Описание ошибки %2", НоменклатураОбъект.Наименование, ОписаниеОшибки()); Сообщение = Новый СообщениеПользователю; Сообщение.Текст = ТекстСообщения; Сообщение.Сообщить(); КонецПопытки; КонецЦикла; КонецПроцедуры
После выполнения команды получаем восстановленные артикулы в справочнике Номенклатура. Частичное восстановление данных выполнено.