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