Как исключить тип из определяемого типа с помощью расширения в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает необходимость изменить состав Определяемого типа, заложенного в типовой конфигурации. Типичная ситуация: в основной конфигурации ОпределяемыйТип.ФизическиеЛица включает в себя типы Строка и СправочникСсылка.ФизическиеЛица. Разработчик хочет с помощью расширения оставить только ссылку на справочник, убрав возможность ввода текста. Рассмотрим, почему стандартное «снятие галочки» в расширении не дает результата, и выясним, какие существуют обходные пути для решения этой задачи.

Анализируем механизм объединения метаданных (Аддитивность)

Первое и самое важное, что нам необходимо усвоить: механизм расширений в 1С работает по принципу дополнения (аддитивности). Когда мы заимствуем Определяемый тип в расширение, платформа не создает его копию, которую можно резать по своему усмотрению. Она создает «настройку», которая будет наложена поверх основной конфигурации.

Проанализируем ситуацию: если в основной конфигурации тип определен как Строка, а в расширении вы добавляете СправочникСсылка.ФизическиеЛица, итоговым типом в базе данных станет Составной тип, включающий и строку, и справочник. Даже если вы визуально снимете флажок с типа Строка в окне редактирования состава типа внутри расширения, платформа проигнорирует это действие. Для системы это означает лишь то, что расширение «не добавляет ничего своего к этому конкретному типу», но тип из основной конфигурации никуда не исчезает.

Почему платформа запрещает исключение типов?

Разберем причину такого поведения с точки зрения целостности системы. Представьте, что в основной конфигурации написан программный код, который жестко рассчитывает на то, что реквизит может содержать строку. Например:


// Код в основной конфигурации
Если ТипЗнч(Объект.Владелец) = Тип("Строка") Тогда
    Сообщить("Владелец задан текстом: " + Объект.Владелец);
КонецЕсли;

Если бы расширение могло физически удалить тип Строка из метаданных, этот код вызвал бы критическую ошибку при выполнении или, как минимум, логическую ошибку в работе алгоритма. Платформа гарантирует, что расширение не может «сломать» ожидания основного кода относительно состава типов.

Проблема «Минимального состава» и визуальные заблуждения

Многих разработчиков вводит в заблуждение интерфейс конфигуратора. Возможность снять галочку существует, но она не несет функциональной нагрузки для типов, которые уже есть в основной конфигурации. Это свойство интерфейса нужно лишь для того, чтобы вы могли управлять типами, которые добавлены другими расширениями или были добавлены вами ранее и теперь стали не нужны.

Важно понимать: итоговый состав типов — это результат объединения всех типов из всех активных расширений и основной конфигурации. Если хотя бы в одном месте тип указан, он будет присутствовать в итоговой структуре Metadata.

Решение 1: Ограничение типа на уровне конкретного реквизита

Если нам нужно запретить использование строки не во всей системе сразу, а в конкретном поле справочника или документа, мы можем прибегнуть к подмене типа самого реквизита. Рассмотрим этот вариант подробнее:

  1. Заимствуем в расширение объект (например, справочник Договоры), где используется этот определяемый тип.
  2. Находим нужный реквизит.
  3. В расширении меняем его тип с ОпределяемыйТип.ФизическиеЛица на конкретный СправочникСсылка.ФизическиеЛица.

В этом случае мы сужаем тип для конкретного поля. Платформа это позволяет, так как СправочникСсылка.ФизическиеЛица входит в состав исходного определяемого типа, и это не нарушает физическую структуру хранения данных (просто часть полей в таблице БД не будет заполняться). Однако помните, что это изменение придется тиражировать на все объекты, где используется данный реквизит.

Решение 2: Программное ограничение выбора в формах

Если ваша задача — сделать так, чтобы пользователь не мог выбрать строку в интерфейсе, рассмотрите вариант использования события НачалоВыбора. Это наиболее гибкий и безопасный метод, не затрагивающий структуру метаданных.

Рассмотрим пример кода в расширении для формы объекта:


&НаКлиенте
Процедура Расш1_РеквизитФизическоеЛицоНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    // Запрещаем стандартный выбор типа, если он предлагается платформой
    СтандартнаяОбработка = Ложь;
    
    // Формируем список типов, которые мы ХОТИМ разрешить
    МассивТипов = Новый Массив;
    МассивТипов.Добавить(Тип("СправочникСсылка.ФизическиеЛица"));
    
    ОписаниеОграниченногоТипа = Новый ОписаниеТипов(МассивТипов);
    
    // Открываем форму выбора конкретного справочника
    ПараметрыВыбора = Новый Структура;
    ПараметрыВыбора.Вставить("ВыборТипа", Ложь); // Отключаем диалог выбора типа
    
    ОткрытьФорму("Справочник.ФизическиеЛица.ФормаВыбора", ПараметрыВыбора, Элемент);

КонецПроцедуры

Решение 3: Использование метода ОписаниеТипов.ИсключитьТипы()

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


// Получаем полное описание типа из метаданных
ИсходноеОписание = Метаданные.ОпределяемыеТипы.ФизическиеЛица.Тип;

// Указываем, какие типы мы хотим убрать
МассивИсключаемыхТипов = Новый Массив;
МассивИсключаемыхТипов.Добавить(Тип("Строка"));

// Создаем новое описание типа без лишних элементов
ОграниченноеОписание = ИсходноеОписание.ИсключитьТипы(МассивИсключаемыхТипов);

// Теперь ОграниченноеОписание можно использовать, например, для реквизитов формы
// ЭтаОперация.ИзменитьРеквизиты(ДобавляемыеРеквизиты);

Этот метод позволяет «вычесть» тип на уровне программного объекта ОписаниеТипов, но он никак не меняет структуру таблиц в базе данных СУБД.

Влияние на физическую структуру данных

Выясним, что происходит «под капотом» базы данных. При использовании составных типов (каким является Определяемый тип со строкой и ссылкой) 1С создает в таблице СУБД несколько колонок для одного реквизита:

Даже если вы программно запретите ввод строки, колонка для хранения строки в таблице БД останется. Расширение не может удалять колонки, созданные основной конфигурацией. Это еще одна причина, почему «удаление» типа через расширение не является физическим удалением типа.

Выводы и рекомендации

Проанализировав механизмы платформы, мы пришли к следующим выводам:

  1. Исключить тип невозможно: Платформа 1С работает только на расширение состава типов Определяемого типа.
  2. Интерфейсные решения: Используйте событие НачалоВыбора и свойство ОграничениеТипа в свойствах элементов формы для фильтрации доступных пользователю вариантов.
  3. Программные фильтры: Применяйте ОписаниеТипов.ИсключитьТипы() в тех алгоритмах, где состав типов проверяется динамически.
  4. Архитектурный совет: Если типовой Определяемый тип категорически не подходит под ваши задачи, лучшей практикой будет создание своего Определяемого типа в расширении и постепенный перевод нужных реквизитов на него, хотя это и потребует большего объема работ по заимствованию объектов.

Помните, что излишнее увлечение изменением типов в расширениях может привести к трудностям при обновлении основной конфигурации и конфликтам, если в системе установлено несколько расширений от разных разработчиков.

← На главную