При выгрузке данных или формировании сложных отчетов в платформе 1С:Предприятие 7.7 разработчики часто сталкиваются со специфическим поведением системы при обработке пустых или некорректных («битых») ссылок. Особенно остро эта проблема проявляется при экспорте данных во внешние форматы, такие как DBF, с использованием встроенного объекта XBase. Нетипизированные или некорректно заполненные поля мгновенно вызывают фатальную ошибку «Несоответствие типов».
В этой статье мы подробно разберем, почему стандартная функция ПустоеЗначение() пропускает битые ссылки, как правильно осуществлять проверку на существование объекта в базе данных, и как корректно выгружать данные в DBF-таблицы без сбоев.
Для начала давайте разберем внутреннее устройство ссылочных типов данных в 1С 7.7. Любая ссылка на элемент справочника или документ физически хранит внутри себя уникальный идентификатор (ID) объекта в базе данных.
ПустоеЗначение(Ссылка) всегда возвращает 1 (Истина).<Объект не найден>.Поскольку внутри битой ссылки физически записан ID (пусть и несуществующий), платформа считает эту переменную заполненной. В результате функция ПустоеЗначение() возвращает 0 (Ложь), и программа пытается работать с объектом как с валидным, что приводит к ошибкам.
Единственным штатным и стопроцентно надежным способом проверить, существует ли объект в базе данных 1С 7.7, является использование предопределенного метода Выбран(). Этот метод выполняет обращение к таблице базы данных и проверяет физическое наличие строки с указанным ID.
Давайте посмотрим на пример безопасного условия:
Если ПустоеЗначение(Запрос.Партия) = 0 Тогда
Если Запрос.Партия.Выбран() = 1 Тогда
// Ссылка заполнена и реально существует в базе данных
ИмяПартии = Запрос.Партия.Наименование;
Иначе
// Это битая ссылка (<Объект не найден>)
ИмяПартии = "Неизвестная партия (битая ссылка)";
КонецЕсли;
Иначе
// Ссылка изначально пустая
ИмяПартии = "Партия не указана";
КонецЕсли;
Важное предупреждение о производительности: Метод ПустоеЗначение() выполняется мгновенно в оперативной памяти компьютера. Метод Выбран() заставляет платформу обращаться к диску или SQL-серверу для проверки записи. Применение метода Выбран() внутри тяжелых циклов (перебор сотен тысяч строк выборки запроса) может существенно снизить скорость работы алгоритма. Поэтому всегда сначала проверяйте значение через быстрый метод ПустоеЗначение(), и только если оно не пустое — применяйте Выбран().
Иногда полезно предварительно отсечь ситуации, когда в реквизит неопределенного типа (или при работе с результатами запросов) попало значение не того типа, который мы ожидаем. Для этого мы можем использовать функцию ТипЗначенияСтр().
Рассмотрим пример проверки типа перед обращением к свойствам объекта:
ТипОбъекта = ТипЗначенияСтр(Запрос.Партия);
Если Найти(ТипОбъекта, "Справочник") > 0 Тогда
Если Запрос.Партия.Выбран() = 1 Тогда
// Мы точно уверены, что это существующий справочник
Сообщить(Запрос.Партия.ТекущийЭлемент());
КонецЕсли;
КонецЕсли;
Обратите внимание, что для битой ссылки функция ТипЗначенияСтр() все равно вернет тип "Справочник" (или конкретный вид, например, "Справочник.Партии"), поскольку тип данных определяется метаданными реквизита, а не фактическим наличием строки в таблице БД.
Часто программисты сталкиваются с тем, что код проверки на пустое значение вроде бы написан верно, но при записи строки в объект XBase (DBF-файл) программа аварийно завершает работу с ошибкой несоответствия типов.
Проанализируем причину. В DBF-файлах все поля имеют строго заданные типы (например, Строка, Число, Дата). Если поле в DBF-файле определено как Числовое ("N"), а мы при обнаружении пустой или битой партии пытаемся записать туда пустую ссылку 1С, пустую строку "" или значение типа Null, объект XBase выдаст ошибку.
Чтобы избежать этого, мы должны явно инициализировать дефолтные «пустые» значения для выгрузки в зависимости от типа поля в DBF. Разберем правильный шаблон заполнения полей DBF:
// Создаем объект для работы с DBF
БД = СоздатьОбъект("XBase");
БД.ОткрытьФайл(КаталогПользователя() + "export.dbf");
Запрос = СоздатьОбъект("Запрос");
// ... тут текст запроса и его выполнение ...
Пока Запрос.Группировка() = 1 Цикл
БД.Добавить();
// Безопасно получаем значение партии
ТекущаяПартия = Запрос.Партия;
Если (ПустоеЗначение(ТекущаяПартия) = 0) И (ТекущаяПартия.Выбран() = 1) Тогда
// Если партия реально существует, заполняем данные
БД.PART_ID = ТекущаяПартия.Код;
БД.PART_NAME = ТекущаяПартия.Наименование;
БД.PRICE = Запрос.СуммаОстаток;
Иначе
// Если партия пустая или битая — пишем строго дефолтные типы!
БД.PART_ID = "00000"; // пустая строка нужного размера
БД.PART_NAME = "Партия не определена";
БД.PRICE = 0; // строго числовое значение 0 для числового поля!
EndIf;
БД.Записать();
КонецЦикла;
БД.ЗакрытьФайл();
Использование явного приведения типов и явного присвоения дефолтных значений (число 0 для числовых полей DBF, пустая строка для текстовых) полностью решает проблему падения выгрузки.
Если в ваших регистрах регулярно всплывают остатки по битым ссылкам (когда движения по партии нет, а остаток висит, либо сама партия удалена), это свидетельствует о нарушении ссылочной целостности базы данных. Борьба с этим на уровне кода отчетов — это устранение симптомов, а не самой болезни.
Для глобального решения проблемы выполните следующие действия:
После выполнения тестирования и исправления все битые ссылки превратятся либо в реальные пустые значения, либо в автоматически созданные элементы справочника, что позволит вашему стандартному коду работать стабильно и быстро.