gifts2017

Восстановление битых ссылок в 1С

Опубликовал Роман Романов (romansun) в раздел Администрирование - Поиск данных

Простая и относительно бескровная методика восстановления битых ссылок и ссылочной целостности.

Столкнулся сегодня с проблемой, известной в 1С как "<Объект не найден>".

Собственно, проблема такая иногда возникала и обычно решалась средствами SQL. Но тут с серверной версией базы возникли проблемы, а битые ссылки надо устранять...

 

Вкратце суть:

<Объект не найден> (9659:ab2b001b78e134e011dfec0814418025)

То, что указано за фразой "Объект не найден" - это совершенно конкретное указание что и где необходимо восстановить. Т.е., в моём случае,

"9659" - это номер таблицы (_Reference9659)

 "ab2b001b78e134e011dfec0814418025" - это как раз та самая пресловутая ссылка, а по сути, просто значение в формате binary(16). В таблице SQL оно выглядит как "0xab2b001b78e134e011dfec0814418025"

Т.е., если сильно упрощенно, достаточно завести в таблице "_Reference9659" новую запись с этим значением в поле "_IDRRef" и всё. Новый элемент появится в справочнике и во всех связных объектах.


Как всё это осуществить средствами 1С?

Простой и бескровный способ - воспользоваться двумя замечательными командами:

ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр().

Загружаем резервную копию базы (все же делают регулярные бэкапы, ведь так?), ищем ссылку, которая была удалена и преобразуем её через ЗначениеВСтрокуВнутр(ИскомаяСсылка) в строку вида "{"#",54c3544f-651b-4887-ae3a-2df362efbacb,9659:ab2b001b78e134e011dfec0814418025}", где мы уже видим знакомые цифры.

 В рабочей копии применяем обратную команду ЗначениеИзСтрокиВнутр("{""#"",54c3544f-651b-4887-ae3a-2df362efbacb,9659:ab2b001b78e134e011dfec0814418025}"). Не забудьте про двойные кавычки вокруг решетки! Результатом будет как раз тот самый <Объект не найден> ссылочного типа. На а дальше применяем УстановитьСсылкуНового().

 

Общий вид кода будет таким:


НовЭл = Справочники.БюджетныеЦентры.СоздатьЭлемент();

НовЭл.УстановитьСсылкуНового(ЗначениеИзСтрокиВнутр("{""#"",54c3544f-651b-4887-ae3a-2df362efbacb,9659:ab2b001b78e134e011dfec0814418025}"));

НовЭл.Наименование = "ДКР";
...
НовЭл.Записать();

 

 
 Данный способ позволит очень быстро восстановить ссылочную целостность даже в файловой базе в полном объёме. В случае, если вы каким-либо образом удалили половину таблицы, то не составит труда написать обычную переливку, к примеру ТЗ, через ЗначениеВФайл()/ЗначениеИзФайла().

 

P.S. В принципе, стандартный инструмент базы "Тестирование и исправление" делает тоже самое, он восстанавливает главное - объект с правильной ссылкой. Но созданный таким образом объект, конечно, не имеет никаких данных внутри. Простой тест на стандартной УТ с удалением и восстановлением номенклатуры выявил на свет целую тонну ошибок конфигуратора при попытки открыть эту номенклатуру, при попытке открыть документы с восстановленной номенклатурой и пр.

 

Буду рад любым комментариям.

См. также

Подписаться Добавить вознаграждение

Комментарии

1. strelez (strelez) 20.01.11 15:24
Прекрасная статья! Благодарю! Реально помогла в решении насущных срочных проблем :!: :!: :!:
Новиков; +1 Ответить
2. Алексей Новиков (Новиков) 20.01.11 15:45
Отличная статья! Спасибо! Надеюсь автор продолжит радовать нас столь замечательными статьями. Все коротко и по делу.

Так держать!
3. ediks (ediks) 21.01.11 07:44
А не проще было воспользоваться типовой обработкой "Выгрузка и загрузка XML", чем изобретать велосипед что-то свое? Она делает все то же самое. Более того, она имеет возможность по умолчанию выгружать все реквизиты по ссылкам, которые, кстати, тоже могут могут иметь битые ссылки в приемнике.
4. Роман Романов (romansun) 21.01.11 11:26
Да, согласен, разных способов много. "Выгрузка и загрузка XML" - отличный вариант.


Дело в том, что в моём случае нет прямого доступа к живой базе. И самым оптимальным и неломаемым вариантом обработки для обслуживающего базу персонала будет обработка с одной кнопкой "Сделать всё и правильно" :). Да и на инструменты сложнее одной кнопки, в принципе, могут потребовать документацию.

Повторюсь, это не обработка, это именно методика.
5. ediks (ediks) 21.01.11 12:18
(4)ОК, любой вариант имеет право на жизнь, если он наилучшим образом решает поставленную задачу. Если эта методика реально помогла восстановить битые ссылки с наименьшими затратами, то это только приветствуется.
6. Роман Романов (romansun) 21.01.11 12:23
7. г. Казань Рустем Гумеров (Rustig) 24.01.11 13:47
(0) можно еще использовать такой вариант:

//получаем уникальный идентификатор ссылки
СтрокаУникальныйИдентификатор = Строка(АвансовыйОтчет.Ссылка.УникальныйИдентификатор());

//выгружаем уникальный идентификатор в строку и
//выгружаем всю информацию по документу с привязкой к уникальному идентификатору
//....


//загружаем данные ...
Док = Документы.АвансовыйОтчет.СоздатьДокумент();
Док.УстановитьСсылкуНового(Документы.АвансовыйОтчет.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаУникальныйИдентификатор)));
Док.Дата
= ТекущаяДата();
//заполняем реквизиты ...
Док.Записать();

Отрывок из статьи "Особенности использования сериализации" на ИТС: "...в 1с 8 методы ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр() реализованы в основном для сохранения функциональной совместимости с 1с 7.7..." - мало что поясняет... может кто примером объяснит?
8. Роман Романов (romansun) 24.01.11 14:37
(7)
Объяснить в смысле что? Разницу в вариантах?

По поводу приведенного варианта - да, это, в общем, то же самое. Только здесь используется ПолучитьСсылку() и УникальныйИдентификатор().
Этот способ, в принципе, классический :). Мне только он не нравится тем, что здесь нет типизации ссылки. Поясняю.
Вот, что выдает нам УникальныйИдентификатор() и ЗначениеВСтрокуВнутр() от одной и той же ссылки соответственно:

"14418025-ec08-11df-ab2b-001b78e134e0"
"{"#",54c3544f-651b-4887-ae3a-2df362efbacb,9659:ab2b001b78e134e011dfec0814418025}"

По сути, первый вариант - это та же ссылка, только "перемешанная". В чем смысл этого? Тут я хз :). Но в первом варианте отсутствует информация откуда, из какой таблицы взята ссылка. Поэтому, чтобы правильно привязать её к таблице, мы вынуждены указывать конкретно, от какого объекта метаданных ссылка Документы.АвансовыйОтчет.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаУникальныйИдентификатор)), либо (если не знаем тип заранее) писать цикл по метаданным и пытаться получить ссылку поочередно от всех объектов.

Что никак не хорошо.

Ну и плюс УникальныйИдентификатор() всё-таки полезен скорее для другого, чем для переноса ссылок - для генерации новой ссылки и возможности подстановки её в нужное место еще до записи самой сгенеренной ссылки.
9. Галина Галина (a4a) 15.12.11 15:35
10. bugmeoncemore (maxdot) 15.12.11 15:51
Для себя нового ничего не узнал, но спасибо за труды. Дал ссылку нескольим товарищям, им помогло! =)
11. Гость 20.02.12 00:23
Спасибо, очень пригодилась
12. Алексей Ко (Жолтокнижниг) 17.01.13 12:33
А не проще получить объект ссылки в нормальной базе, серилизовать его.
объект=Ссылка.ПолучитьОбъект();
ЗаписатьXML(записьХМЛ,объект);


А в базе с битыми ссылками просто прочитать и записать этот объект.

прочитанноеЗначение=ПрочитатьXML(чтениеХМЛ);
прочитанноеЗначение.записать();
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа