Меню

Практика освоения ABAP CDS для непрограммистов. Часть 4

|

Публикация предназначена для консультантов по различным модулям SAP ERP. Описываемая технология ABAP CDS наиболее актуальна для систем SAP S/4HANA, но может применяться и в любых системах, начиная с платформы SAP Netweaver 7.40 SPS05, независимо от используемой базы данных.

Часть 1  Часть 2  Часть 3

Продолжение статьи.

5. АССОЦИАЦИИ, PATH EXPRESSIONS И ИХ ИСПОЛЬЗОВАНИЕ В ДЕМОНСТРАЦИОННОЙ МОДЕЛИ

5.1. Основная идея

5.2. Простейший пример

5.3. Path Expressions

5.4. Синтаксические правила ассоциаций, сравнение с JOIN, кардинальность

5.4.1 Синтаксические правила описания ассоциаций

5.4.2 Различие между ассоциацией и оператором JOIN

5.4.3 Кардинальность ассоциаций

5.5. Аннотация @AbapCatalog.compiler.compareFilter

5.6. Развитие демонстрационной модели с помощью ассоциаций и Foreign Keys

5. АССОЦИАЦИИ, PATH EXPRESSIONS И ИХ ИСПОЛЬЗОВАНИЕ В ДЕМОНСТРАЦИОННОЙ МОДЕЛИ

5.1. Основная идея

Ассоциации – это элементы VDM, которые позволяют моделировать взаимосвязи между входящими в модель сущностями (таблицами и ракурсами). Примером такой связи между двумя таблицами является соединение их данных по общим полям, обозначаемое в SQL как операция join. Например, в SAP ERP для различных документов (FI-проводки, поставки, заказы) данные заголовков и данные позиций документов хранятся в отдельных таблицах. Чтобы получить полную информацию о документе, необходимо выполнить join между таблицей заголовков и таблицей позиций по полю «номер документа».

Идея создания ассоциаций в VDM заключалась в том, чтобы не просто отразить такие взаимосвязи, но и сделать их частью модели данных, вписать их в метаданные CDS-ракурсов и тем самым обеспечить их повторное использование. Ассоциация описывается в каком-то CDS-ракурсе один раз, и там ей может быть присвоен псевдоним (alias). А все последующие сущности, использующие этот ракурс, могут просто ссылаться на ассоциацию по присвоенному псевдониму. Как говорилось, VDM строится иерархически, снизу вверх, в несколько уровней. Таким же образом «вырастают» один из другого и CDS-ракурсы: базовые, композитные, ракурсы использования. В этом смысле соотношения между ракурсами можно представить себе как древовидный граф. Тогда ассоциации – это рёбра графа, так как они отражают взаимосвязи между вершинами. Приложение-потребитель имеет дело с ракурсами использования, то есть  с самой «вершиной» такого дерева. От вершины древовидного графа можно спуститься, переходя от одной вершины к другой по связующим их рёбрам, до самых нижних вершин. Таким же образом и повторное использование ассоциаций позволяет получать информацию с самого нижнего уровня VDM без повторного явного «прописывания» всех полей на каждом уровне модели. Такое повторное прописывание хорошо знакомо тем, кто имеет опыт создания HANA Calculation Vews. Подчас такая работа становится утомительной и рутинной. А изменение HANA-модели на нижнем уровне требует тщательного контроля всех вышележащих уровней, так как целостность модели нарушается. Использование ассоциаций в VDM значительно упрощает эти аспекты моделирования. И в этом существенное отличие и преимущество ассоциаций по сравнению с обычными операциями join. Хотя и эти последние тоже могут использоваться в DDL.

5.2. Простейший пример

Продолжим создание демонстрационной модели. На простейшем примере легче всего проиллюстрировать синтаксис создания ассоциаций.

В предыдущих разделах создан ракурс ZI_AIRLINE, представляющий собой основные данные из справочника авиакомпаний, таблицы SCARR. Как ракурс-справочник он имеет категорию данных #DIMENSION. Но та же таблица, помимо основных данных, содержит и тексты – названия авиакомпаний. Определим интерфейсный ракурс ZI_AIRLINETEXT, как показано на Рис.102.

Рис.102. Код ракурса ZI_AIRLINETEXT

Большинство использованных аннотаций уже описаны ранее. Как отмечалось, аннотация @ObjectModel.dataCategory: #TEXT используется при создании ракурсов, содержащих зависящие от языка тексты. Для таких ракурсов в число ключевых полей добавляется явно описанное поле «язык». Здесь это поле указано в строке 11 с соответствующей аннотацией в строке 10. Но поскольку в таблице SCARR такого поля нет, то строки 10-11 закомментированы. Они включены в данный пример только для иллюстрации возможности создания текстов, зависящих от языка. Также можно отметить, что аннотация @EndUserText.label: 'Airline Name' использована дважды. На уровне DDL-источника в целом (строка 3) она задаёт словесное название ракурса. А перед полем carrname (строка 13) эта же аннотация указывает, что при просмотре данных ракурса это поле будет видно под заголовком «Airline Name».

Итак, у нас есть ракурсы ZI_AIRLINE и ZI_AIRLINETEXT. Чтобы максимально упростить первый пример ассоциации, оба ракурса используют только одну таблицу SCARR и имеют одинаковые ключевые поля Airline, идущие из исходного поля carrid. Ракурс ZI_AIRLINE  содержит основные данные, поэтому при создании ассоциации он является источником (source entity). А ракурс ZI_AIRLINETEXT  присоединяется к источнику через ассоциацию, то есть является целью ассоциации (target entity). Ассоциация описывается после названия источника данных и перед открывающей фигурной скобкой с перечислением полей (см. Рис.103).

Рис.103. Определение ассоциации ракурсов ZI_AIRLINE и ZI_AIRLINETEXT

Здесь в квадратных скобках указана так называемая кардинальность ассоциации, то есть возможное количество записей в target entity, соответствующих одной записи в source entity. Подробнее о кардинальности сказано далее.

В качестве псевдонима (alias) для присоединяемой ассоциации указано имя _Text. Начинать псевдоним ассоциации с нижнего подчёркивания – это рекомендуемая практика. Она позволяет избежать путаницы (случайного совпадения) между названиями полей и названиями ассоциаций.

В строке 10 вместо имени source entity использовано служебное слово $projection. Это также стандартный элемент DDL-синтаксиса. Его назначение описано далее.

Слева от строки 9 видна пиктограмма – желтый треугольник с восклицательным знаком. Это предупреждение. Его текст всплывает, если подвести указатель мыши к пиктограмме (см. Рис.104).

Рис.104. Просмотр сообщения с предупреждением в коде DDL Source

Здесь подразумевается, что ассоциация не используется в числе полей, выбираемых оператором SELECT и перечисленных внутри фигурных скобок. Далее этот список полей будем называть SELECT-лист. Чтобы устранить данное предупреждение, можно просто включить в  SELECT-лист всю ассоциацию целиком (в строке 17). См. Рис.105.

Рис.105. Публикация ассоциации для возможности её повторного использования

Уже было отмечено, что ассоциации позволяют передавать данные по иерархии ракурсов VDM «снизу вверх» без детального прописывания и перечисления отдельных полей. И данный пример иллюстрирует эту возможность. Вместо всех полей, входящих в ракурс ZI_AIRLINETEXT, указан только псевдоним соответствующей ассоциации. Теперь все ракурсы, которые будут использовать ZI_AIRLINE, смогут также задействовать и поля из ZI_AIRLINETEXT, ссылаясь на них по псевдониму ассоциации. В следующем разделе это будет более детально проиллюстрировано при разборе понятия Path Expressions.

Отметим, как созданная ассоциация отразилась в Outline (см. Рис.106).

Рис.106. Графическое отражение ассоциаций в Outline

Также Outline позволяет определить список других ракурсов, использующих текущий ракурс. Чтобы узнать это, нужно в Outline правой кнопкой мыши вызвать контекстное меню на техническом имени ракурса. И выбрать команду «Get Where-used List». На примере ZI_AIRLINETEXT это показывает Рис.107

Рис.107. Поиск ракурсов, использующих текущий ракурс

В результате в нижней части окна SAP HANA Studio на закладке Search появится список ракурсов, использующих текущий ракурс. И будет указано, каким именно способом используется текущий ракурс. Например – является целью ассоциации, или является источником, из которого выбираются поля в SELECT-лист. В нашем примере будет показано, что ракурс ZI_AIRLINE использует ZI_AIRLINETEXT в качестве target entity для ассоциации (см. Рис.108).

Рис.108. Результат поиска по Where-Used List

5.3. Path Expressions

В описанном выше примере определена ассоциация _Text. И она включена в SELECT-лист.

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

  1. В ракурсе VIEW1 определена ассоциация _Assoc1. В составе таблицы, присоединённой к VIEW1 через эту ассоциацию, есть ряд полей, например – поле element. Ассоциация _Assoc1 включена в SELECT-лист полей ракурса.
  2. Определён ракурс VIEW2, к которому с помощью ассоциации _Assoc2 присоединён ракурс VIEW1. При этом ассоциация _Assoc2 также опубликована в SELECT-листе ракурса VIEW2
  3. Определен ракурс VIEW3, к которому с помощью ассоциации _Assoc3 присоединён ракурс VIEW2. Ассоциация _Assoc3 опубликована в SELECT-листе ракурса VIEW3.

Теперь перед нами стоит задача: получить в ракурсе VIEW3 значение поля element и вписать его отдельно в SELECT-лист ракурса. Это можно сделать с помощью следующего выражения:_Assoc3._Assoc2._Assoc1.element

Использованный в этом примере приём DDL-синтаксиса, перечисляющий цепочку последовательных ассоциаций, называется Path Expression. В примере длина цепочки составила три ассоциации. На практике, разумеется, их может быть как больше, так и меньше. Простейшим примером для Path Expression является использованное ранее в демонстрационном примере включение одиночной ассоциации _Text в SELECT-лист ракурса ZI_AIRLINE.

Цепочка Path Expression может оканчиваться как отдельным полем (как в приведённом примере), так и ассоциацией. При этом действуют следующие правила:

  • Если окончанием цепочки является поле, то это должно быть поле из target entity в последней ассоциации цепочки.
  • Если окончанием цепочки является ассоциация, то её роль определяется тем местом в DDL-источнике, где использована цепочка. При использовании цепочки в SELECT-листе конечная ассоциация становится элементом этого листа. Она будет доступна для использования в последующих CDS-ракурсах. Именно это происходит с ассоциацией _Text в SELECT-листе ракурса ZI_AIRLINE.
  • Если окончанием цепочки является ассоциация, а при этом сама цепочка перечислена после оператора FROM, то такая ассоциация считается источником (target или source).
  • DDL-синтаксис, определяющий ракурсы, использует OpenSQL. Поэтому в DDL Source, помимо оператора FROM или SELECT-листа могут использоваться и традиционные SQL-конструкции с операторами WHERE или HAVING. По самому смыслу таких операторов, в них должны быть описаны только ограничения на отдельные поля. Поэтому использовать Path Expression после WHERE или HAVING можно только при условии, что цепочка заканчивается отдельным полем.

В демонстрационном примере использован простейший случай Path Expression с одной ассоциацией _Text. Теперь приведём пример из официальной документации SAP, демонстрирующий значительно более широкие и гибкие возможности применения ассоциаций и Path Expressions. Вначале определим ракурс sales_order с ассоциацией _note_header:

@AbapCatalog.sqlViewName: 'SALES_ORDER_VW' 
define view sales_order as 
  select from snwd_so 
         association [0..1] to snwd_text_key as _note_header 
           on $projection.note_guid = _note_header.node_key 
  { * }

Использование символа * в последней строке означает, что в SELECT-лист вошли все поля обеих таблиц, включённых в ассоциацию.

Следующий ракурс присоединяет sales_order к таблице snwd_bpa:

@AbapCatalog.sqlViewName: 'BPA_VW' 
define view business_partner as 
  select from snwd_bpa 
         association [0..*] to sales_order as _sales_order 
           on $projection.node_key = _sales_order.buyer_guid 

  { * }

Наконец, третий ракурс использует эти две ассоциации, а также определяет ещё одну:

@AbapCatalog.sqlViewName: 'SALESO_INV_VW' 
define view invoice as 
  select from 
         business_partner._sales_order[ 
           lifecycle_status <> 'C' and lifecycle_status <> 'X'] 
           as bpa_so
         association [0..1] to snwd_so_inv_head as _invoice_header 
           on $projection.node_key = _invoice_header.so_guid 
        { key bpa_so.node_key,
              bpa_so.so_id, 
              bpa_so.note_guid,
              bpa_so.lifecycle_status, 
              _invoice_header.dunning_level, 
              bpa_so._note_header } 
          where _invoice_header.dunning_level > '0'

В этом ракурсе использованы следующие приёмы:

  1. Ассоциация _sales_order вызвана через ракурс business_partner с помощью Path Expression
  2. Ассоциация _sales_order вызвана с добавлением к ней дополнительных условий фильтрации по полю lifecycle_status
  3. Для полученного в результате пп.1-2 источника назначен псевдоним bpa_so
  4. Определена новая ассоциация _invoice_header
  5. SELECT-лист содержит поле bpa_so.node_key, входящее в условие «ON» ассоциации _invoice_header. Также в лист включено поле bpa_so.note_guid, входящее в условие «ON» ассоциации _note_header. Прямое перечисление ON-полей в SELECT-листе является необходимым условием при использовании ассоциаций (см. следующий раздел).
  6. Ассоциация _invoice_header не опубликована в SELECT-листе полностью, то есть не может быть использована в последующих ракурсах. Из этой ассоциации взято только поле dunning_level
  7. В операторе WHERE использован Path Expression с ассоциацией _invoice_header. Как сказано выше, в таком случае Path Expression обязан заканчиваться отдельным полем, на которое и действует условие WHERE.

5.4. Синтаксические правила ассоциаций, сравнение с JOIN, кардинальность

Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland

У вас уже есть учетная запись?

Войти

Обсуждения Количество комментариев1

Комментарий от  

Иван Рыбкин

  |  02 марта 2019, 00:09

Добрый вечер.  На рис 116 пропущено объявление ассоциации _AirportFrom -  немного сбивает с толку.  Спасибо за статью !