При активной работе в программе 1С:Управление торговлей редакции 10.3 пользователи часто сталкиваются с нарушением ссылочной целостности базы данных. Одна из самых распространенных и неприятных проблем — появление «битых ссылок» вида <Объект не найден> в реквизитах карточки номенклатуры, отвечающих за единицы измерения (хранения остатков, отчетов или базовой единицы). Попытки исправить проблему интерактивно через интерфейс обычно приводят к системным предупреждениям о том, что эти единицы уже задействованы в существующих документах или регистрах накопления.
В этой статье мы подробно проанализируем причины возникновения данной коллизии, разберем архитектурные особенности хранения единиц измерения в УТ 10.3 и рассмотрим несколько практических методов программного восстановления битых ссылок без выполнения полного тестирования и исправления (ТИИ) базы данных.
Чаще всего подобная проблема является следствием некорректного слияния дублей номенклатуры или неудачного переноса данных при обмене. Рассмотрим классический сценарий:
ЕдиницыИзмерения была физически удалена из информационной базы.<Объект не найден> (уникальный_идентификатор_GUID).Ситуация осложняется тем, что справочник ЕдиницыИзмерения в УТ 10.3 является подчиненным справочнику Номенклатура. Это означает, что каждая единица хранения или отчетов жестко привязана к своему владельцу. Просто выбрать новую единицу в карточке товара система не позволяет, так как старая битая ссылка намертво заблокирована транзакциями прошлых периодов.
Прежде чем приступать к исправлению, важно понимать разницу между реквизитами единиц в карточке номенклатуры:
КлассификаторЕдиницИзмерения. Он не подчинен номенклатуре и содержит общие элементы (например, «шт», «кг», «м»).ЕдиницыИзмерения. Каждая запись здесь уникальна для конкретного товара и содержит коэффициент пересчета относительно базовой единицы.Если повреждены именно подчиненные единицы, нам необходимо физически восстановить элементы справочника ЕдиницыИзмерения с теми же уникальными идентификаторами (GUID), которые остались в транзакционных таблицах.
Если физические элементы единиц измерения остались в базе, но при замене дублей у них сбился владелец или возникли несоответствия при записи номенклатуры, можно воспользоваться принудительной записью в режиме обмена данными. Этот способ подходит для точечного исправления конкретной позиции, когда сами элементы единиц существуют, но не привязаны должным образом к карточке товара.
Рассмотрим следующий алгоритм:
Процедура ВосстановитьСвязьЕдиниц(НоменклатураСсылка, ЕдиницаОтчетовСсылка, ЕдиницаХраненияСсылка, БазоваяЕдиницаСсылка)
// Принудительно устанавливаем правильного владельца для подчиненных единиц
ЗафиксироватьВладельцаЕдиницы(ЕдиницаОтчетовСсылка, НоменклатураСсылка);
ЗафиксироватьВладельцаЕдиницы(ЕдиницаХраненияСсылка, НоменклатураСсылка);
// Получаем объект номенклатуры для изменения реквизитов
НомОбъект = НоменклатураСсылка.ПолучитьОбъект();
// Включаем режим загрузки для отключения стандартных прикладных проверок конфигурации
НомОбъект.ОбменДанными.Загрузка = Истина;
НомОбъект.БазоваяЕдиницаИзмерения = БазоваяЕдиницаСсылка;
НомОбъект.ЕдиницаДляОтчетов = ЕдиницаОтчетовСсылка;
НомОбъект.ЕдиницаХраненияОстатков = ЕдиницаХраненияСсылка;
Попытка
НомОбъект.Записать();
Сообщить("Связи единиц измерения успешно обновлены для: " + НомОбъект.Наименование);
Исключение
Сообщить("Не удалось записать номенклатуру: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
КонецПроцедуры
Процедура ЗафиксироватьВладельцаЕдиницы(ЕдиницаСсылка, ВладелецСсылка)
Если ЗначениеЗаполнено(ЕдиницаСсылка) Тогда
ЕдОбъект = ЕдиницаСсылка.ПолучитьОбъект();
Если ЕдОбъект <> Неопределено Тогда
ЕдОбъект.Владелец = ВладелецСсылка;
ЕдОбъект.ОбменДанными.Загрузка = Истина;
ЕдОбъект.Записать();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: Использование свойства ОбменДанными.Загрузка = Истина позволяет обойти проверки, написанные разработчиками в модуле объекта номенклатуры (например, запрет на изменение единиц при наличии движений). Однако этот метод сработает только в том случае, если сами элементы единиц физически присутствуют в базе данных СУБД. Если элементы удалены безвозвратно, этот способ выдаст ошибку, так как метод ПолучитьОбъект() вернет значение Неопределено.
Если единицы измерения были полностью удалены физически, нам поможет технология воссоздания элементов по их оригинальному уникальному идентификатору (GUID). Метод платформы 1С УстановитьСсылкуНового() позволяет создать новый элемент справочника с заранее определенным идентификатором ссылки.
Многие программисты совершают методологическую ошибку, пытаясь распарсить строковое представление битой ссылки <Объект не найден>, чтобы извлечь из него текстовый GUID и затем преобразовать его обратно. Делать это совершенно не нужно! Сама по себе переменная, хранящая битую ссылку, уже содержит внутри себя полноценный GUID на уровне СУБД.
Проанализируем правильный, лаконичный и быстрый способ извлечения GUID и воссоздания удаленного подчиненного элемента справочника ЕдиницыИзмерения:
Процедура ВосстановитьБитуюЕдиницу(БитаяСсылкаНаЕдиницу, СсылкаНаНоменклатуруВладельца, ИмяЕдиницы = "шт", КоэффициентПересчета = 1)
// Проверим, действительно ли ссылка является битой
Если БитаяСсылкаНаЕдиницу.ПолучитьОбъект() = Неопределено И Не БитаяСсылкаНаЕдиницу.Пустая() Тогда
// Получаем уникальный идентификатор напрямую из битой ссылки
ИстинныйGUID = БитаяСсылкаНаЕдиницу.УникальныйИдентификатор();
// Создаем новый элемент в справочнике ЕдиницыИзмерения
НоваяЕдиница = Справочники.ЕдиницыИзмерения.СоздатьЭлемент();
// Принудительно сопоставляем новый объект со старым GUID
НоваяЕдиница.УстановитьСсылкуНового(Справочники.ЕдиницыИзмерения.ПолучитьСсылку(ИстинныйGUID));
// Заполняем обязательные реквизиты
НоваяЕдиница.Владелец = СсылкаНаНоменклатуруВладельца;
НоваяЕдиница.Наименование = ИмяЕдиницы;
НоваяЕдиница.Коэффициент = КоэффициентПересчета;
Попытка
НоваяЕдиница.Записать();
Сообщить("Успешно воссоздан элемент справочника ЕдиницыИзмерения с GUID: " + Строка(ИстинныйGUID));
Исключение
Сообщить("Ошибка записи воссозданной единицы: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
Иначе
Сообщить("Ссылка корректна или пуста, восстановление не требуется.", СтатусСообщения.Информация);
КонецЕсли;
КонецПроцедуры
После записи восстановленной единицы измерения все исторические документы, движения регистров накопления и бухгалтерии моментально «подхватят» вновь созданный элемент. Ссылка перестанет быть битой, и в отчетах вместо технического текста снова отобразится понятное пользователю наименование.
Если битых ссылок накопилось много, мы можем автоматизировать этот процесс. Напишем универсальный запрос, который быстро найдет все позиции номенклатуры с нарушенной целостностью в части единиц хранения остатков, и восстановит их в цикле:
Процедура АвтоматическоеВосстановлениеЕдиниц()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК НоменклатураСсылка,
| Номенклатура.ЕдиницаХраненияОстатков КАК БитаяСсылкаХранения,
| Номенклатура.БазоваяЕдиницаИзмерения КАК БазоваяЕдиница
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЕдиницаХраненияОстатков <> ЗНАЧЕНИЕ(Справочник.ЕдиницыИзмерения.ПустаяСсылка)
| И Номенклатура.ЕдиницаХраненияОстатков.Ссылка ЕСТЬ NULL";
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Поврежденных ссылок в справочнике Номенклатура не обнаружено.");
Возврат;
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Определим наименование базовой единицы для подстановки
ИмяБазовойЕдиницы = "шт";
Если ЗначениеЗаполнено(Выборка.БазоваяЕдиница) Тогда
ИмяБазовойЕдиницы = СокращенноЛП(Выборка.БазоваяЕдиница.Наименование);
КонецЕсли;
// Восстанавливаем объект в базе данных
ВосстановитьБитуюЕдиницу(Выборка.БитаяСсылкаХранения, Выборка.НоменклатураСсылка, ИмяБазовойЕдиницы, 1);
КонецЦикла;
КонецПроцедуры
Этот скрипт работает быстро и безопасно. Он анализирует базу данных на уровне метаданных с помощью конструкции Номенклатура.ЕдиницаХраненияОстатков.Ссылка ЕСТЬ NULL, что позволяет мгновенно отфильтровать битые ссылки без перебора всей базы на клиенте.
Если у вас есть архивная копия базы данных, созданная до момента неудачной замены дублей, вы можете обойтись без написания кода:
ЕдиницыИзмерения. Настройте отбор по владельцам (необходимым карточкам номенклатуры) или списку GUID, если они вам известны.Поскольку выгрузка-загрузка XML сохраняет неизменными внутренние идентификаторы GUID, все битые ссылки мгновенно восстановятся в их первозданном виде со всеми прежними реквизитами и настройками.
Используя приведенные методики, вы сможете быстро и безопасно навести порядок в справочниках 1С:Управление торговлей 10.3, избежав длительного процесса тестирования и исправления базы данных и не нарушив при этом оперативную работу пользователей.