CDS(Core Data Service)View是S/4HANA里重要的建模方式之一。下面是S/4HANA的架构图,可以很清晰的看到CDS View在整个架构中的重要地位:S/4HANA里大部分ABAP代码对底层数据的事务操作(Transactional Logic, 即数据读和写)和报表分析逻辑(Analytic Logic), 几乎都基于构造于底层数据库表的CDS View来进行,而不像SAP Business Suite那样,直接操作底层的数据库表。
CDS View从其名称来分析,它首先仍然是一个数据库视图,将底层数据库表的某些字段暴露给消费者。同时CDS View提供的功能远远不局限于传统的数据库视图,SAP围绕着CDS View打造了一系列框架,本文要阐述的则是S/4HANA里基于CDS View模型的OData开发的具体操作与实现。
1
在深入S/4HANA OData开发之前,我们首先回顾SAP OData开发的演进路线。SAP成都研究院的Jerry Wang曾经在他的公众号文章 SAP OData编程指南里讲述SAP Business Suite系统里OData的开发,可以简单归纳成以下步骤:
1. 在事务码SE11里创建OData模型需要的ABAP数据类型。
2. 在事务码SEGW里创建OData模型。OData模型是一个树形结构,由1个根节点和若干个子节点构成。父子节点间的关联通过navigation实现。激活OData模型,自动生成OData模型的元数据提供类(MPC)和业务数据提供类(DPC)。
3. 在事务码SE24或者SE80里对MPC和DPC进行ABAP编程。
可以看出Business Suite里的OData开发需要使用三种不同的开发工具,前两步可以概括为建模,而第三步则是具体编程实现。而OData实现的工作量主要集中在第三步。然而,我们试想这个场景,以Opportunity和Lead这两个模型的OData实现举例,除了它们底层数据库表的具体字段可能有所差异之外,围绕着这些模型进行的读,写和搜索的代码,必然有很多相似之处,那么用Business Suite这种开发方式,必然会造成在DPC的ABAP编码里有很多相似的代码出现。
因此,在S/4HANA里引入了一种全新的OData开发方式:基于CDS View的元数据驱动开发(Metadata-Driven Development)。所谓元数据驱动,意即开发人员只需要把精力花在CDS View这个元数据的开发上,至于围绕着CDS View的数据读取逻辑,则由S/4HANA的框架处理了,无需开发人员再手动编写代码。
2
我们先来看看S/4HANA标准的Fiori应用,Product Master,是如何贯彻基于CDS View的元数据驱动开发的思路的。S/4HANA Fiori Launchpad里点击Product Master tile来访问这个Fiori应用:
在Chrome开发者工具的Network标签页观察到S/4HANA里Product Master这个Fiori应用基于的OData服务名称为 MD_C_PRODUCT_MAINTAIN_SRV:
到S/4HANA的后台系统,使用事务码SEGW打开这个OData服务对应的模型, 在Data Source References->Exposures via SADL->CDS-Entity Exposures里能看到这个OData模型基于的CDS View是:C_Product
我们用ABAP Development Studio,在包VDM_MD_PRODUCT里能找到CDS View C_Product,可以看到它又是基于I_ProductWD这个View构建的。我们再打开I_ProductWD,依次类推,最后发现这些View基于的数据库表就是MARA,也就是我们熟悉的物料主数据的数据库表。
现在,就让我们来模仿S/4HANA的C_Product, 动手通过CDS View开发一个OData服务。
因为CDS View还是得基于一张实际的数据库表创建,因此我们先创建一张简单的数据库表,里面的记录用于描述一本图书的ID,名称和作者。
插入三条数据:
然后基于数据库表ZBOOK创建一个CDS View: C_Book。这里我们也仿照S/4HANA Product Master的CDS View的命名规范,前缀C指Consumption(消费)。源码如下:
第一行的注解@AbapCatalog.sqlViewName定义了该CDS View在事务码SE11里对应生成的视图名称为ZCBOOK。可以在SE11里根据该名称打开它。
第二行@AccessControl.authorizationCheck:指定该CDS View的权限检查方式。因为本文出于演示目的,不需要进行权限检查。
在自动完成列表里能看到这个注解其他的可选值:
第三行@EndUserText.label:该CDS View的描述信息,能在其他消费CDS View的框架中被读取,比如出现在前面展示的SE11里的Short Description字段。
第四行@ClientHandling.algorithm:我选择的是#SESSION_VARIABLE,这样一旦运行时该CDS View对应的数据被读取时,ABAP框架会自动在Where语句中添加一个client处理语句。我们来看个例子。
执行下面这行ABAP语句:
SELECT * INTO TABLE @DATA(lt_table) FROM c_book.
用ST05观测,发现ABAP框架悄悄地添加了一个WHERE "MANDT" = '001', 确保只有当前登录Client的数据被读取出来。
这也是为什么@ClientHandling.algorithm的值选择为#SESSION_VARIABLE后,CDS View生成的ABAP视图会自动出现一个MANDT字段:
CDS View开发完成之后,我们可以用该View生成一个OData服务了。
事务码SEGW,创建一个新的OData项目:
使用右键菜单Data Model->Reference->Data Source:
输入我们之前创建的CDS View名称:C_Book:
此时在文件夹Exposures via SADL下面就能看见我们导入的CDS View对应的数据类型了,这个SADL我们马上会介绍。点击"Generate Runtinme Objects",生成DPC和MPC。
围绕着ZBOOK这张表的OData服务就生成好了——我们并没有做任何ABAP编程来实现ZBOOK表里数据的读取,这些都是S/4HANA里的SADL(Service Adaptation Definition Language)自动实现的。
我们先对自动生成的OData服务进行测试。把刚才自动生成的OData服务名字抄下来:MD_BOOK_SRV
使用事务码/IWFND/MAINT_SERVICE,点击“Add Service":
在External Service Name里填入OData服务的名称,点击"Get Services"按钮,选中结果,再点"Add Selected Services":
然后这个OData服务就会出现在Service Catalog列表下了,点击SAP Gateway Client即可开始测试了。
Request URI维护成/sap/opu/odata/sap/MD_BOOK_SRV/?$metadata&$format=xml,点Execute按钮,就能成功返回该OData服务的metadata。当然用浏览器测试也行。
使用如下的URL, 即可通过OData服务读取CDS View C_Book里的全部内容:
/sap/opu/odata/sap/MD_BOOK_SRV/c_book
可以看到三本书的内容都成功读取出来了。
3
最后要介绍的就是SADL。到目前为止,我们只是进行了CDS View开发并将View导入SEGW的项目里,自动生成了OData服务,然而并未进行一行的ABAP编码。这正体现了前面提到的Metadata-Driven Development——元数据编程思路的优越之处:开发人员只需要关注于用CDS View进行业务模型的设计,运行时的读取,交由SADL框架来完成。
我们在类CL_SQL_STATEMENT的方法EXECUTE_QUERY设置断点,然后再次打开访问URL /sap/opu/odata/sap/MD_BOOK_SRV/c_book,断点触发:
从调用栈能看出通过构建于CDS View之上的OData服务读取数据,经历了几个不同的框架调用:
1. SAP Gateway框架类,就是图中以命令空间/IWFND开头的类,负责接收从浏览器发送过来的OData请求,根据请求URL里包含的MD_BOOK_SRV这一OData服务名,分发给对应的DPC类CL_MD_BOOK_DPC。
2. 因为CL_MD_BOOK_DPC的代码是通过事务码SEGW自动生成的,里面没有应用开发人员编写的逻辑,而是把调用转交给SADL框架。
3. SADL框架负责把请求映射成对应的SQL语句,通过一个SAP内部函数调用C_DB_FUNCTION进行数据读取:
这就是S/4HANA里通过CDS View构造的OData的工作原理,感谢阅读。