在路径表达式中使用关联

学习目标

  • 在 CDS 视图中使用路径表达式。

  • 在路径表达式中使用过滤条件。

  • 在 ABAP SQL 中使用路径表达式。

CDS 中的路径表达式

CDS 视图实体从具有公开关联的实体读取时,有两种可能性:

传播关联

通过将关联名称添加到元素列表,关联也会对此视图的使用者可见。在示例中,关联 _Department 在视图实体 R_Employee 中定义和公开。视图实体 C_EmployeeR_Employee 读取并传播关联 _Department

使用关联

通过在关联名称后添加句点符号 (.) 和元素名称,关联用于从关联目标读取数据。这种用途称为路径表达式。在示例中,关联 _Department 的目标是 CDS 视图实体 C_Department。CDS 视图实体 C_Employee 使用路径表达式从关联目标中读取字段折旧指定,并将其添加到其自己的元素清单中。

在数据库级别,路径表达式将转换为关联源和关联目标的连接。这将在编辑器的 显示 SQL 创建语句 函数中可见。

在示例中,path expression _Department.DepmentSpecation 导致连接数据库中的 SQL 视图 R_EMPLOYEE 和 R_DEPARTMENT。连接的 ON 条件派生自关联的 ON 条件。

注意

连接类型 LEFT OUTER MANY TO ONE JOIN 是 SAP HANA 数据库的特殊类型。还有一种连接类型 LEFT OUTER MANY TO MANY JOIN,在关联基数的最大值大于 1 时使用。

需要强调的是,只有在路径表达式中使用关联时,才在数据库级别构建连接。定义、公开和传播关联不会导致联接。关联的此功能有时称为按需连接

让我们再看一个示例:即使 CDS 视图实体 R_Employee 定义和公开关联 _Department 和 CDS 视图实体 C_Employee 传播此关联,相应的 SQL 视图 C_EMPLOYEE 也只能从 SQL 视图 R_EMPLOYEE 中读取。

到目前为止,我们仅使用一个关联讨论了路径表达式。但您还可以通过链接多个关联来构建更长的路径表达式。

以下是示例:CDS 视图实体 R_Employee 公开关联 _Department,其中将 CDS 视图实体 R_Department 作为目标。此目标公开另一个关联 _Head,指回到 R_Employee,但读取作为相应部门主管的员工。路径表达式 _Department。_Head.LastName 读取员工分配到的部门主管的姓氏。自动生成三个数据源的长而复杂的连接。

大多数情况下,CDS 视图实体定义关联时,会将其公开给其使用者。但是,它也可以直接使用 关联,而不是 ,或者除了公开它之外。

我们将此称为关联的即席使用。在示例中,CDS 视图实体 R_Employee 定义关联 _Department。它直接在路径表达式中使用关联来检索相关部门的指定,而不是公开关联。

如果是即席使用,则立即在此 CDS 视图实体的 SQL 视图中构建连接。

如何在 CDS 中写入路径表达式

播放视频,了解如何在 CDS 中编写路径表达式。

视频:本节含 SAP 官方视频(视频 ID 1_efp6bbxh),需在 learning.sap.com 在线观看。

基数对路径表达式的影响

在路径表达式中使用关联时,基数可能会影响语法检查。编辑器显示"对多"关联错误使用的警告,甚至错误,即基数最大值大于 1 的关联。

在视图定义的 WHERE 子句的路径表达式中,根本不允许使用"对多"关联,并会导致语法错误。

在元素列表中,允许"多个"关联,但编辑器会显示警告,指示此路径表达式可以修改结果集数。

此警告意味着什么?假设您的表仅包含 1 个具有 5 名员工的部门。如果没有路径表达式,CDS 视图 C_Department 仅返回 1 个数据集。然后将具有"多个"关联 _Employee 的路径表达式添加到元素列表。之后,同一视图返回 5 个数据集,每个员工一个。这可能会误导视图 C_Department 的消费者,因为他们期望每个部门有一个数据集。

提示

如果您对员工数据和部门数据的组合感兴趣,应从视图 R_Employee 开始,并使用 "to one" 关联 _Department 添加部门详细信息。

正确使用"对多"关联的一种方法是将路径表达式放置在聚合中。GROUP-BY-子句对于聚合是必需的,可确保数据集的数量保持不变。在此示例中,CDS 视图实体 C_Department 仍为每个部门返回一个数据集,而不是为每个员工返回一个数据集。

注意

正确使用"对多"关联的另一种方法是添加过滤条件。我们将在下一部分中讨论过滤器。

试用:错误且正确使用对多”关联

  1. 创建以 /DMO/I_Connection_R 作为参考数据对象的新 CDS 数据定义。

  2. 移除元素列表,包括花括号。

  3. 复制以下代码片段并将其插入到 as select from /DMO/I_Connection_R 之后:

{
key AirlineID,
key ConnectionID,
// _Airline.CurrencyCode,
// _Flight.PlaneType,
DepartureAirport,
DestinationAirport
}
where
AirlineID = 'LH'          // Only one connection
and ConnectionID = '0400' // fulfills this filter
// and _Airline.CurrencyCode = 'EUR'
// and _Flight.PlaneType = '747-400'
  1. 激活数据定义并显示数据预览。由于 WHERE 子句完全限定了转机的主键,因此您只能看到一个数据集。

  2. 从元素列表中的两个路径表达式中移除注释标记。请注意语法警告,因为 _Flight 的基数为 0..* ,因此是"对多"关联。

  3. 尽管出现警告,但仍激活数据定义并显示数据预览。现在,您会看到多个数据集。

  4. 注释 WHERE 子句中的附加条件。请注意包含 _Flight 关联的路径表达式的语法错误。

  5. 移除元素列表和 WHERE 子句并将其替换为以下语法:

{
key AirlineID,
key ConnectionID,
_Flight.OccupiedSeats
//        sum(_Flight.OccupiedSeats) as TotalOccupiedSeats
}
where
AirlineID    = 'LH'   // Only one connection
and ConnectionID = '0400' // fulfills this condition
//  group by
//    AirlineID,
//    ConnectionID
  1. 请注意路径表达式(包括关联 _Flight )的语法警告。激活并显示数据预览。

  2. 注释掉路径表达式,并从集合函数 sum() 和 GROUP BY 子句中删除注释标记。请注意,语法警告已消失,并且数据预览仅显示一个数据集。

路径表达式中的过滤器

在路径表达式中使用关联时,可以添加过滤器以限制关联目标的数据集。过滤条件紧接在关联名称后面的一对方括号 ([ ]) 中。就像在 WHERE 子句中一样,您可以使用关系运算符和布尔运算符 AND、OR、NOT。条件的左侧必须是关联目标的字段。右侧具有更大的灵活性。此外,还可以使用关联目标、文字、内置函数等字段。

在此示例中,有两个路径表达式,一个没有过滤条件,另一个使用过滤条件 OccupiedSeats > MaximumSeats。第一个路径表达式搜索与转机相关联的最早航班,而第二个路径表达式将搜索限制为超额预订的航班,即已占用座位数超过可用座位数的航班。

从技术上讲,过滤条件将添加到数据库级别生成的连接的 ON 条件。

让我们看一下示例中的 SQL create 语句:示例中的第一个联接属于不含过滤器的路径表达式。ON 条件比较 AIRLINEID、CONNECTIONID 和客户端字段 MANDT。第二个联接属于具有 过滤器的路径表达式。是否可以从过滤的路径表达式中找出附加条件?

当您过滤基数最大大于 1 的关联时,可能会发生在应用过滤器后仅保留一个关联目标条目的情况。过滤器将"多个"关联转换为"对一"关联。在这种情况下,应在过滤条件前添加 "1: " 以记录关联的更改基数。

在此示例中,CDS 视图实体 I_Currency 定义和公开关联 _Text,这是"对多"关联,以不同语言返回货币名称。如果没有过滤器,关联将以系统中维护的所有语言读取货币的名称。但是,具有过滤器的两个路径表达式仅读取一个货币名称(英语或德语)。

如前所述,在聚合之外的路径表达式中使用"对多"关联时,语法检查会发出警告和错误。但是,如果过滤器确保只有一个记录,会发生什么?语法检查是否仍发出警告和错误?是的,这样做是因为它不知道过滤器将"多个"关联转换为"对一个"关联。我们可以通过在过滤器条件的方括号中添加 "1:" 来对此进行记录。在此示例中,对于过滤器为 Language = 'E' 的路径表达式,存在语法警告。但含过滤器 1: Language = 'D' 的路径表达式没有语法警告。

试用:过滤关联

  1. 创建以 /DMO/I_Connection_R 作为参考数据对象的新 CDS 数据定义。

  2. 移除元素列表,包括花括号。

  3. 复制以下代码片段并将其插入到 as select from /DMO/I_Connection_R 之后:

{
key AirlineID,
key ConnectionID,
//_Airline._Currency._Text.CurrencyName
//_Airline._Currency._Text[ Language = 'E' ].CurrencyName
//_Airline._Currency._Text[ 1: language = 'E' ].CurrencyName
}
where
AirlineID    = 'AA'
and ConnectionID = '0017'
  1. 从第一个路径表达式中删除注释标记,并分析语法警告(如果有)。

  2. 为此版本的视图激活数据定义并显示数据预览和 SQL create 语句。

  3. 注释掉第一个路径表达式,并从第二个路径表达式中移除注释标记。

  4. 激活并分析包含过滤器的路径表达式的语法警告、数据预览和 SQL create 语句。

  5. 对第三个路径表达式重复上述步骤。

ABAP SQL 中的路径表达式

使用公开关联的另一种方法是使用 ABAP SQL 中的路径表达式。该概念与 CDS 中的概念完全相同,但语法略有不同。

最重要的语法区别如下:

关联前缀

在 ABAP SQL 路径表达式中,必须使用反斜线 () 对关联进行转义。

元素选择器

在 CDS 路径表达式中,句点 (.) 用作关联名称和元素名称之间的分隔符。在 ABAP SQL 中,期间符号不适用,因为它会结束语句。因此,在 ABAP SQL 中,连字符用作元素选择器。

让我们看一个示例:此 ABAP SQL SELECT 语句从公开关联 _Airline 的 CDS 视图实体 /DMO/I_Connection_R 中读取。FIELDS 列表中的最后一个表达式是从关联目标 /DMO/I_Carrier 中读取元素 Name 的路径表达式。

另一个语法差异与链接关联相关。当路径表达式包含关联序列时,没有专用分隔符。在 CDS 中,关联由句号 (.) 分隔,在 ABAP SQL 中彼此直接相邻。但请注意,每个关联名称都需要一个反斜线 () 作为前缀。

在此示例中,关联 _Airline 的目标公开返回航空公司本币详细信息的关联 _Currency。表达式 \_Airline\_Currency-CurrencyISOCode 读取经营转机的航空公司本币的 ISO 代码。

注意

在 CDS 中,相同的路径表达式为 _Airline._Currency.CurrencyISOCode

在 ABAP SQL 中,筛选条件添加到方括号中,就像在 CDS 中一样。但是,要指定基数,将使用完全不同的语法。您必须添加关键字 MANY TO ONE WHERE,而不是 "1:"。还有其他几个选项,例如一个 TO ONE WHERE 和 MANY TO MANY WHERE。有关详细信息,请参阅 ABAP 关键字文档。

注意

存在一种替代语法,在其中编写 [ (1) WHERE … ] 而不是 [ MANY TO ONE WHERE … ],但不建议使用此替代语法。

试用:ABAP SQL 中的路径表达式

  1. 创建实施接口 IF_OO_ADT_CLASSRUN 的新全局类。

  2. 将以下代码片段复制到方法 if_oo_adt_classrun~main() 的实施部分:

* Data selection
**********************************************************************
SELECT FROM /dmo/i_connection_R
FIELDS Airlineid,
connectionid,
*                 _Airline.Name,
*                \_Airline-Name,
*                 _Airline-Name,
*                 _Airline~Name,
*                \_Airline~Name,
*
*                \_Airline-_Currency-CurrencyISOCode,
*                \_Airline-\_Currency-CurrencyISOCode,
*                \_Airline\_Currency-CurrencyISOCode,
*                \_Airline~\_Currency~CurrencyISOCode,
*                \_Airline\_Currency~CurrencyISOCode,
*
*                \_Airline\_Currency\_Text[                     Language = 'E' ]-CurrencyShortName AS CurrencyNameEN,
*                \_Airline\_Currency\_Text[   MANY TO ONE WHERE Language = 'D' ]-CurrencyShortName AS CurrencyNameDE,
*                \_Airline\_Currency\_Text[                     Language = 'E' ]-CurrencyShortName AS CurrencyNameEN,
*                \_Airline-\_Currency-\_Text[ MANY TO ONE WHERE Language = 'D' ]-CurrencyShortName AS CurrencyNameDE,
*                \_Airline~\_Currency~\_Text[ 1:                Language = 'E' ]-CurrencyShortName AS CurrencyNameEN,
DepartureAirport,
DestinationAirport
INTO TABLE @DATA(result).
* Output
**********************************************************************
out->write(  data = result
name = 'Selection result').

此编码包含带有各种路径表达式的 ABAP SQL SELECT 语句。 3. 从路径表达式的第一个块中移除注释,并使用语法检查查找 ABAP SQL 中语法正确的路径表达式。 4. 移除语法错误的变式,激活类,将其作为控制台应用执行,并分析控制台输出。 5. 对第二个和第三个路径表达式块重复此操作。

在路径表达式中使用关联

您已定义具有公开关联的 CDS 视图实体。您想要使用公开的关联。首先在 CDS 视图中执行此操作,然后在 ABAP SQL 的 SELECT 语句中执行此操作。

模板:

  • /LRN/CL_S4D430_RLT_PATH_EXP(全局类)

解决方案:

  • /LRN/C_EMPLOYEE_QRY(数据定义)

  • /LRN/CL_S4D430_RLS_PATH_EXP(全局类)

任务 1: 在 CDS 中使用公开关联

定义新的 CDS 视图实体(建议名称:Z##_C_EmployeeQuery)。使用公开关联的员工数据的视图实体作为数据源(建议名称为 Z##_R_Employee)。在元素清单中,读取员工标识和姓名。然后,添加路径表达式以读取部门描述和部门助理的姓氏。

注意

如果尚未完成上一练习,则可以让新的视图实体从 /LRN/R_Employee_Rel 视图实体中读取。

步骤

  1. 在您自己的包中,创建新的数据定义(建议名称:Z##_C_EMPLOYEEQUERY,其中 ## 是您的组编号)。指定 CDS 视图实体 Z##_R_Employee 作为参考对象,然后选择定义视图实体模板以生成定义语句、某些标准注释和元素列表。

  2. 在项目浏览器视图中,右键单击数据定义 Z##_R_EMPLOYEE 以打开上下文菜单。

  3. 从上下文菜单中,选择新建数据定义

  4. 确认字段包含包的名称,并且参考对象字段包含数据库表定义的名称。

  5. 名称字段中,输入 CDS 视图实体的名称(Z##_C_EmployeeQuery,其中 ## 是您的组编号)。

  6. 描述字段中输入**员工(查询)**,然后选择下一步

  7. 确认传输请求,然后选择下一步

警告

确保尚未选择完成。如果执行此操作,则无法选择要使用的模板。

  1. 模板列表中,选择定义视图实体,然后选择完成

  2. 应用源代码格式设置。

  3. 从 eclipse 菜单中选择 源代码格式 。或者,选择 Shift + F1

  4. 编辑新数据定义的元素列表。移除除 EmployeeIDFirstNameLastNameDepartmentID 和公开关联 _Department 之外的所有元素。

  5. 如下调整代码:

define view entity Z##_C_EmployeeQuery
as select from Z##_R_Employee
{
key EmployeeId,
FirstName,
LastName,
DepartmentID,
/* Associations */
_Department
}
  1. DepartmentID 元素之后,添加路径表达式以读取员工分配到的部门的描述(建议元素名称:DepartmentDescription)。

  2. 如下调整代码:

define view entity Z##_C_EmployeeQuery
as select from Z##_R_Employee
{
key EmployeeId,
FirstName,
LastName,
DepartmentID,
_Department.Description as DepartmentDescription,
/* Associations */
_Department
}
  1. 保存数据定义并显示 SQL CREATE 语句。

注意

如果不保存数据定义,您的更改将不会出现在 SQL CREATE 语句中。

  1. Ctrl + S 保存开发对象。

  2. 右键单击数据定义源代码中的任意位置,然后选择显示 SQL CREATE 语句

  3. 添加路径表达式以读取部门助理的姓氏(建议元素名称:AssistantName)。

  4. 如下调整代码:

define view entity Z##_C_EmployeeQuery
as select from Z##_R_Employee
{
key EmployeeId,
FirstName,
LastName,
DepartmentID,
_Department.Description as DepartmentDescription,
_Department._Assistant.LastName as AssistantName,
/* Associations */
_Department
}
  1. 激活数据定义并再次显示 SQL CREATE 语句。

  2. Ctrl + F3 激活开发对象。

  3. 右键单击数据定义源代码中的任意位置,然后选择显示 SQL CREATE 语句

  4. 在数据预览工具中显示查询结果。

  5. 将光标放在数据定义中的任意位置,然后按 F8 调用数据预览工具。

任务 2: 在 ABAP SQL 中使用公开关联

创建 ABAP 类 /LRN/CL_S4D430_RLT_PATH_EXPR(建议名称:ZCL_##_PATH_EXPR)的副本并调整 SELECT 语句。从刚创建的 CDS 视图实体(建议名称为 Z##_C_EmployeeQuery)中读取所有字段。此外,在 ABAP SQL 中实施路径表达式以读取部门主管的名称。

步骤

  1. /LRN/CL_S4D430_RLT_PATH_EXPR 类复制到您自己的包中的类(建议名称:ZCL_##_PATH_EXPR,其中 ## 代表组编号)。

  2. 在项目浏览器视图中,右键单击 /LRN/CL_S4D430_RLT_PATH_EXP 类以打开上下文菜单。

  3. 从上下文菜单中,选择复制 ....

  4. 在包字段中输入的名称。在名称字段中,输入名称 ZCL_##_PATH_EXP,其中 ## 是您的组编号。

  5. 调整描述,然后选择下一步

  6. 确认传输请求并选择完成

  7. IF_OO_ADT_CLASSRUN~MAIN 方法中,更改 SELECT 语句。将 FROM 子句中的 /LRN/C_Employee_Ann 替换为您刚刚创建的 CDS 视图实体的名称 (Z##_C_EmployeeQuery)。

  8. 如下调整代码:

SELECT
FROM Z##_C_EmployeeQuery
FIELDS employeeid,
  1. 在字段清单末尾,还可以读取新视图元素 DepartmentDescriptionAssistantName

  2. 如下调整代码:

SELECT
FROM Z##_C_EmployeeQuery
FIELDS employeeid,
firstname,
lastname,
departmentid,
departmentdescription,
assistantname
INTO TABLE @DATA(result).
  1. 在部门助理的姓名之后,实施读取部门主管姓氏的路径表达式(建议字段名称:HEADNAME)。

提示

尽可能使用代码完整化。请记住,在 ABAP SQL 中,关联名称需要反斜线符号 () 作为前缀,并在关联名称和元素名称之间使用破折号 (-)。

  1. 如下调整代码:

SELECT
FROM Z##_C_EmployeeQuery
FIELDS employeeid,
firstname,
lastname,
departmentid,
departmentdescription,
assistantname,
\_department\_head-lastname AS headname
INTO TABLE @DATA(result).
  1. 激活全局类并将其作为控制台应用执行。

  2. Ctrl + F3 激活开发对象。

  3. F9 将全局类作为控制台应用执行。