Почему свойство Источник.Типы() подписок на события в 1С возвращает весь список объектов, а не только отмеченные?

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

Когда мы работаем с подписками на события в 1С:Предприятии, нам часто требуется программно анализировать их источники. Однако иногда мы сталкиваемся с неочевидным поведением свойства Метаданные.ПодпискиНаСобытия.<ИмяПодписки>.Источник.Типы(), которое, казалось бы, должно возвращать только те объекты, которые явно отмечены в конфигураторе. Вместо этого мы можем получить полный список всех объектов соответствующего типа, даже если некоторые из них были исключены. Давайте подробно разберем, почему это происходит и как правильно интерпретировать данную ситуацию.

Суть проблемы: Несоответствие ожиданий и реальности

Представим, что у нас есть подписка на событие, например, "ПриЗаписиОбъекта", которая должна срабатывать для документов и справочников. В конфигураторе мы открываем свойства подписки и видим, что в разделе "Источник" выбрана общая группа, например, "ДокументСсылка" или "ВсеСсылки". При этом, если мы развернем эту группу, мы можем обнаружить, что из всего списка документов или справочников вручную сняты галочки с нескольких конкретных объектов, которые не должны попадать под действие подписки.

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


КоличествоТипов = Метаданные.ПодпискиНаСобытия.ПриЗаписиОбъектаКонтрольЗаписи.Источник.Типы().Количество();

может неожиданно вернуть число, соответствующее общему количеству всех документов или всех справочников в конфигурации, а не только тех, которые явно помечены. Например, если в конфигурации 411 документов и 415 справочников, а подписка формально распространяется на "ВсеДокументы" и "ВсеСправочники" с несколькими исключениями, мы можем получить в результате 826 (411+415) или близкое к этому значение, что совершенно не соответствует нашему представлению об "отмеченных" объектах.

Это может привести к вопросам: "Почему так происходит?" и "Как тогда получить реальный список объектов, на которые распространяется подписка?"

Разбираемся в механизме: Как 1С обрабатывает источники подписок

Для того чтобы понять это поведение, рассмотрим, как платформа 1С интерпретирует выбор источников подписки в конфигураторе.

1. "ВсеСсылки" и другие общие типы – это интерфейсная абстракция

Когда мы устанавливаем галочку на общем типе, таком как ДокументСсылка, СправочникСсылка или даже ВсеСсылки, в конфигураторе, это является удобной абстракцией для интерфейса пользователя. Эта галочка фактически означает, что подписка потенциально распространяется на все объекты, принадлежащие к этой категории. Система 1С не хранит в метаданных подписки точный "список всех отмеченных объектов", когда выбран общий тип, а скорее записывает, что источником является обобщенный тип.

Сообщения из форума подтверждают это: "типы СправочникСсылка/ДокументСсылка/.../ЛюбаяСсылка - это фикция, только для интерфейса, реально же всегда массив конкретных типов хранится". Важно понимать, что когда вы выбираете такой обобщенный тип, в метаданных подписки сохраняется указание на него как на общий источник. И именно этот общий тип вы и получаете при обращении к Источник.Типы().

2. Исключения через снятие галочек – это дополнительная логика, а не изменение источника

Когда вы снимаете галочки с отдельных объектов внутри выбранной общей категории (например, с конкретных документов "ЗаказПокупателя" или справочников "Контрагенты"), вы фактически настраиваете список исключений. Эти исключения обрабатываются платформой на этапе выполнения, а не меняют фундаментальное определение источника подписки в метаданных. То есть, источник по-прежнему считается "ДокументСсылка", но с учетом внутренних правил, которые говорят: "для этих конкретных документов (с которых снята галочка) подписка не применяется".

Таким образом, когда мы программно обращаемся к Метаданные.ПодпискиНаСобытия.<ИмяПодписки>.Источник.Типы(), мы получаем перечень всех типов прикладных объектов, на события которых может осуществляться подписка в рамках выбранной общей категории. Это означает, что метод Типы() возвращает коллекцию всех возможных типов, которые относятся к "ДокументСсылка" или "ВсеСсылки" в вашей конфигурации, независимо от того, были ли с них сняты отдельные галочки.

3. Почему 1С реализовала это именно так?

Разработчики платформы 1С применили такой подход не случайно. Рассмотрим основные причины:

  1. Удобство конфигурирования: Представьте, что в типовой конфигурации 400 документов и 300 справочников. Если нам нужно, чтобы подписка работала для почти всех документов, за исключением 5-10 конкретных, гораздо удобнее поставить одну галочку на "ВсеДокументы" и снять всего 5-10, чем вручную проставлять галочки на 390+ документах. Этот подход значительно упрощает первоначальную настройку подписок в больших конфигурациях.

  2. Автоматическая обработка новых объектов: Если вы выбираете общий тип, например, "ДокументСсылка", все новые документы, которые будут добавлены в конфигурацию в будущем (например, при обновлении или собственной доработке), автоматически попадают под действие этой подписки, если только вы специально не исключите их. Это позволяет избежать ручной донастройки подписок при каждом изменении метаданных.

  3. Гибкость и контроль: Этот механизм дает разработчику возможность тонко управлять подписками. Вы можете глобально распространить подписку, а затем выборочно исключить объекты, для которых ее применение нежелательно или не имеет смысла.

Как получить "реальный" список объектов, подпадающих под действие подписки?

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

Вместо того чтобы пытаться получить этот детальный список из метаданных подписки, существует другой, более эффективный и предусмотренный платформой подход:

1. Проверка типа объекта внутри процедуры-обработчика

Самый распространенный и рекомендуемый способ – это проверять тип объекта непосредственно внутри общего модуля-обработчика подписки. В большинстве случаев это именно то, что нам нужно, поскольку подписка срабатывает для конкретного объекта, и мы можем определить, является ли он тем, который мы хотим обрабатывать.

Пример (концептуальный):


// В общем модуле, который является обработчиком подписки "ПриЗаписиОбъектаКонтрольЗаписи"
Процедура ПриЗаписиОбъектаКонтрольЗаписи(Источник, Отказ) Экспорт

    // Проверяем тип объекта, который вызвал событие
    Если ТипЗнч(Источник) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
        // Этот объект исключен из обработки, ничего не делаем
        Возврат;
    КонецЕсли;

    Если ТипЗнч(Источник) = Тип("СправочникСсылка.Валюты") Тогда
        // Этот объект исключен из обработки, ничего не делаем
        Возврат;
    КонецЕсли;
    
    // Если объект не был исключен явно, продолжаем обработку
    // ... Ваш код для обработки события записи ...
    
КонецПроцедуры

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

2. Использование инструментария для анализа подписок

Для более глубокого анализа подписок на события в больших и сложных конфигурациях существуют специализированные инструменты:

  1. Поиск ссылок на объект в конфигураторе: Мы можем использовать стандартную функцию "Поиск ссылок на объект" для конкретного объекта метаданных (например, документа или справочника). Это покажет все места, где данный объект упоминается, включая подписки на события. Это поможет нам выяснить, на какие подписки данный объект явно влияет.

  2. Внешние отчеты и обработки: Существуют различные внешние инструменты, разработанные сообществом 1С, которые позволяют визуально анализировать подписки на события. Такие отчеты могут отображать классы, источники, события и связанные общие модули, давая более наглядное представление о структуре подписок и их влиянии на объекты.

  3. 1C:Enterprise Development Tools (EDT): В более современных средствах разработки, таких как 1C:Enterprise Development Tools (EDT), реализованы более мощные инструменты для анализа метаданных. Например, инструмент "Все подписки на события" в EDT может помочь удобно фильтровать подписки по событию или источнику, предоставляя более детальную информацию.

Выводы

Поведение свойства Метаданные.ПодпискиНаСобытия.<ИмяПодписки>.Источник.Типы(), которое возвращает полный список возможных объектов при выборе общих типов в конфигураторе (даже с индивидуальными исключениями), является особенностью платформы 1С. Эта особенность продиктована удобством конфигурирования и автоматической обработкой новых объектов.

Мы, как программисты, должны понимать, что Источник.Типы() предоставляет информацию о потенциальном охвате подписки, а не о ее фактическом применении с учетом всех исключений, настроенных в конфигураторе. Для определения того, подпадает ли конкретный объект под действие подписки, рекомендуется использовать проверки типа объекта внутри процедуры-обработчика подписки, либо использовать специализированные инструменты для анализа метаданных.

Таким образом, проблема не в "тупости" или "идиотизме" разработчиков 1С, а в том, что поведение платформы в этом конкретном аспекте отличается от интуитивных ожиданий, но имеет под собой вполне логичные и практичные основания. После того как мы осознаем этот нюанс, работа с подписками становится более предсказуемой и управляемой.

← На главную