Работа с определяемыми типами (Defined Types) в системе 1С:Предприятие 8.3 часто вызывает вопросы у разработчиков, особенно когда дело касается написания эффективных запросов. Основная сложность заключается в том, что определяемый тип по своей сути является составным типом данных. Это означает, что поле в базе данных может содержать не одно фиксированное значение, а значения самых разных типов: от ссылок на справочники и документы до примитивных типов, таких как строки или числа.
В этой статье мы разберем, почему стандартные способы проверки на "пустоту" не всегда работают корректно, и рассмотрим наиболее правильные методики решения этой задачи.
Прежде чем переходить к коду запроса, нам необходимо проанализировать, как именно хранятся "пустые" значения в полях составного типа на уровне базы данных. В 1С существует три принципиально разных состояния "пустоты":
Контрагенты), но конкретный элемент справочника не выбран. Для каждого ссылочного типа в 1С существует своя уникальная пустая ссылка.ЛЕВОЕ СОЕДИНЕНИЕ), когда во второй таблице не найдена соответствующая запись.Следовательно, простая проверка ГДЕ Поле ЕСТЬ NULL не найдет пустые ссылки справочников, а проверка ГДЕ Поле = НЕОПРЕДЕЛЕНО пропустит уже инициализированные, но пустые поля ссылочных типов.
Наиболее универсальным и надежным способом является передача в запрос массива, содержащего все возможные варианты "пустоты" для данного определяемого типа. Мы соберем в этот массив значение Неопределено и пустые ссылки всех типов, входящих в состав определяемого типа.
Рассмотрим по шагам, как реализовать этот метод программно:
// 1. Получаем описание типов из метаданных определяемого типа
ОпределяемыйТипМетаданные = Метаданные.ОпределяемыеТипы.ИмяВашегоТипа;
ОписаниеТипов = ОпределяемыйТипМетаданные.Тип;
// 2. Формируем массив пустых значений
МассивПустыхЗначений = Новый Массив;
МассивПустыхЗначений.Добавить(Неопределено);
Для Каждого ТекущийТип Из ОписаниеТипов.Типы() Цикл
// Проверяем, является ли тип ссылочным
Если Справочники.ТипВсеСсылки().СодержитТип(ТекущийТип)
Или Документы.ТипВсеСсылки().СодержитТип(ТекущийТип) Тогда
// Создаем пустую ссылку данного типа
ПустаяСсылка = Новый(ТекущийТип);
МассивПустыхЗначений.Добавить(ПустаяСсылка);
КонецЕсли;
КонецЦикла;
// 3. Устанавливаем параметр в запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Т
|ГДЕ
| Т.РеквизитСоставногоТипа В (&МассивПустыхЗначений)";
Запрос.УстановитьПараметр("МассивПустыхЗначений", МассивПустыхЗначений);
Результат = Запрос.Выполнить();
Преимущество данного метода: Он работает максимально быстро, так как платформа 1С эффективно использует индексы при поиске по массиву значений (оператор В).
Существует альтернативный способ, который позволяет обойтись без формирования массива параметров. Мы можем попытаться обратиться к свойству Ссылка проверяемого поля. Если поле пустое (будь то Неопределено или пустая ссылка), то разыменование ссылки через точку вернет NULL.
Проанализируем пример такого условия в запросе:
ВЫБРАТЬ
Т.Ссылка
ИЗ
Документ.ПриходныйКассовыйОрдер КАК Т
ГДЕ
Т.ОбъектРасчетов.Ссылка ЕСТЬ NULL
Важное предостережение: Несмотря на краткость, этот метод имеет серьезный недостаток. При выполнении такого запроса СУБД вынуждена выполнить LEFT JOIN ко всем таблицам, которые входят в этот составной тип. Если ваш определяемый тип включает в себя десятки документов и справочников, запрос станет крайне тяжелым и медленным. Используйте этот прием только в том случае, если типов в составе немного (2–3 типа).
Если вам нужно найти только те записи, где тип вообще не был выбран (состояние Неопределено), можно использовать функцию языка запросов ТИПЗНАЧЕНИЯ. Выясним, как это выглядит на практике:
ВЫБРАТЬ
Т.Ссылка
ИЗ
Справочник.ДоговорыКонтрагентов КАК Т
ГДЕ
ТИПЗНАЧЕНИЯ(Т.ДокументОснование) = ТИП(НЕОПРЕДЕЛЕНО)
Однако помните, что это условие не выберет записи с пустой ссылкой конкретного типа (например, пустую ссылку справочника Договоры). Поэтому данный метод редко применяется в чистом виде для поиска "пустоты".
Если ваш определяемый тип, помимо ссылок, содержит примитивные типы (Число, Строка, Дата), то понятие "пустое значение" расширяется. Для системы 1С "пустыми" также будут считаться:
""001.01.0001 00:00:00В таком случае при формировании массива из Метода 1 следует добавить и эти значения. Рассмотрим подробнее фрагмент кода для дополнения массива:
Если ОписаниеТипов.СодержитТип(Тип("Строка")) Тогда
МассивПустыхЗначений.Добавить("");
КонецЕсли;
Если ОписаниеТипов.СодержитТип(Тип("Число")) Тогда
МассивПустыхЗначений.Добавить(0);
КонецЕсли;
Если ОписаниеТипов.СодержитТип(Тип("Дата")) Тогда
МассивПустыхЗначений.Добавить('00010101');
КонецЕсли;
Мы проанализировали ситуацию и выяснили, что наиболее правильным подходом является программная подготовка массива всех возможных пустых значений. Это гарантирует корректность результата независимо от того, как именно пользователь "очистил" поле в интерфейсе.
Подведем итог лучшей практики:
Неопределено и ПустаяСсылка.Поле.Ссылка ЕСТЬ NULL для сложных определяемых типов с большим количеством таблиц, чтобы не перегружать SQL-сервер лишними соединениями.Метаданные для динамического получения типов, чтобы ваш код оставался работоспособным даже после изменения состава определяемого типа в конфигураторе.В (&Параметр), так как он лучше всего оптимизирован на уровне СУБД.Соблюдение этих правил позволит вам писать надежные и производительные запросы для любых сложных типов данных в системе 1С.