转自:https://mp.weixin.qq.com/s/iIVfB6yXxS2JK2r0HWYycw
为何会出现CDS?
抛开ABAP不谈,几乎任何一种数据库中,都会有定义数据库表、类型或视图的语句,我们一般叫做DDL(Data Definition Language),当然,很多数据库也提供图形化建模的方式,在你拖来拖去同时,最终实际生成的也是DDL。HANA来自SAP,因为SAP的业务特性,在产品开发过程中,需要经常地关联业务表、创建很多更方便查看的视图、对标准表/视图进行扩展增强、对数据进行权限控制等。将这些从SAP产品开发/实施中逐渐积累的需求汇总,便有了CDS,它包含最基本的DDL功能,但远远不限于此。
HANA CDS vs. ABAP CDS
出于本篇文章的主要目的,下面内容再提到的CDS,都默认指的是ABAP CDS。
CDS View为什么只能看不能摸?
有两种方式:第一种是下载一个通用版本的Eclipse,再安装一个支持ABAP的补丁包。第二种是下载ADT(ABAP Development Tool),直接给你打包好了。两种方式稍有区别,如果你需要开发除ABAP之外的代码,第一种肯定更强大。如果你只需要ABAP相关的开发,第二种更好一些,安装后出错的概率小,也不用关心版本问题。
概括CDS的特点及功能
本文目的不在详细地解读每种语句,但最基础的一些CDS的术语,还是需要介绍一下,这样有利于之后的讨论,也会方便读者更详细地查阅资料。如需查阅详细语法,可以参考Help链接:
@AbapCatalog.sqlViewName: 'CDSFRWK_DEMO_1'@EndUserText.label: 'Calculations in SELECT list'@AbapCatalog.compiler.compareFilter: truedefine view CdsFrwk_Sales_Order_Item as select from snwd_so_i association [1] to snwd_pd as _product on snwd_so_i.product_guid = _product.node_key{ key snwd_so_i.node_key as so_item_guid, parent_key as so_guid, snwd_so_i.product_guid, snwd_so_i.so_item_pos, currency_code, gross_amount, case net_amount when 0 then 0 else cast( ( division( tax_amount, net_amount, 4 ) * 100 ) as abap.dec( 15, 2 ) ) end as tax_rate, division( tax_amount, net_amount, 4 ) * 100 as demo, _product }
这个简单的CDS View包含了以下几个部分/功能:
1. Annotation
@符号之后,冒号之前的一部分(比如EndUserText.label),即为Annotation,我们可以称它为标签。冒号后面的,即为这些标签的值。这些标签简单来讲可以理解为一些配置,CDS的很多功能扩展,基本也都通过此来实现。
它的机制是,当程序执行时,CDS的代码发送给后台,后台会通过CL_DD_DDL_HANDLER的各种方法来解析,并实现相应的功能。而这些标签在后台当然是Hard code的,在接口IF_DD_DDL_ANNOTATIONS的属性中可以找到它们,ADT中F1也可以查看每个标签的相关文档。
虽然看似简单,一个标签,一个值,但很多标签后都是一整套强大的功能。比如EndUserText.label,看名字知道是来定义标签描述,但其背后是可以和翻译功能很好结合的。可以根据上面提到的标签名,自行查询这些标签的详细功能。这里不一一展开。
2. SQL View vs. CDS view entity
简而言之,在你激活的那一刻,一个CDS Entity在ABAP应用层生成,同时HANA数据库层,生成了SQL View。
再次强调,在Open SQL中使用时,要用CDS Entity名,这样能更多地发挥其特性。比如,CDS Entity默认会自动处理Client,你读出的数据会默认为当前Client的数据,这也是我们一般做项目所期望的。但使用SQL View就不会。另一个原因是,CDS Entity所在的Layer可以默认地处理和数据库的连接,而使用SQL View还会像之前传统的Open SQL一样,打开一个ABAP层同数据库层的连接,某种意义上会耗费一些资源(这点我不知如何考证,关于performance问题我会在下面单独聊)。
官方只有建议用CDS Entity,但我并没有找到一个官方文档来列举其技术方便的优势。如有读者看到了,记得发给我学习一下。也有人说今后SAP为了避免混淆,可能会停止支持Open SQL使用SQL View Name。
上面提到的Client的处理,有兴趣的,可以阅读下面的Help,各种场景都是支持的,一般我们也不会用到:
另,我在做Demo的时候,还发现一个有趣的现象。默认情况下,ADT中导航栏里看到的DDL名,就是CDS Entity名,然后下面会有两个子对象:SQL View和CDS Entity。但我尝试在激活前,将CDS Entity的名字改了一下,会发现,也是可以激活的,对比导航栏,这种子对象的关系就消失了。SE11也不能访问。但双击还是可以显示,我估计是有缓存。
而且,激活后,这些名字也是不能再改的,所以激活前要把名定好。不然只能删了重建。
3. Association
define view I_SalesDocumentBasic
as select from vbak
//Association
//--[ GENERATED:012:GlBfhyFV7kY4hGXbseDAyW
association [0..*] to I_BusinessAreaText as _BusinessAreaText on $projection.BusinessArea = _BusinessAreaText.BusinessArea
association [0..*] to I_BusinessAreaText as _CostCenterBusinessAreaText on $projection.CostCenterBusinessArea = _CostCenterBusinessAreaText.BusinessArea
association [0..*] to I_CreditControlAreaText as _CreditControlAreaText on $projection.CreditControlArea = _CreditControlAreaText.CreditControlArea
// ]--GENERATED
association [0..*] to I_SalesDocumentItemBasic as _ItemBasic on $projection.SalesDocument = _ItemBasic.SalesDocument
association [0..1] to I_SDDocumentCategory as _SDDocumentCategory on $projection.SDDocumentCategory = _SDDocumentCategory.SDDocumentCategory
association [0..1] to I_SalesDocumentType as _SalesDocum
entType on $projection.SalesDocumentType = _SalesDocumentType.SalesDocumentType
一个销售订单可能有0到多个行项目,所以它和销售订单行项目数据I_SalesDocumentItemBasic的关系是[0..*],而一个销售订单,只能在定义时有一种确定的类型,所以它和I_SalesDocumentType的关系是[0..1]。
在技术特性方面,有一个词很好地概括了Association的特点:“Lazy Join”。系统如果根据Cardinality判断出某条数据在被结合的数据实体中没有值,那它就不去真的Join,这某种程度上对性能很有帮助。但同样的SQL,如果Cardinality不同,最终出现的结果可能也完全不同,在使用时还是要彻底弄清其含义。
所以,我们在之后项目中,如果熟练掌握了这些对象结构,便不用再去费力地寻找各个表之间的关系,针对一组业务对象,直接从一个定义好的CDS Entity,便可以方便快速地获取我们需要的信息。
4. 条件语句
你看到的CASE语句,即为一种条件语句,在一些简单情况下,我们不必再取出所有相关字段,再通过LOOP中进行条件控制。直接将其写在SQL中即可。
5. 内置函数
值得一提的是,字符串处理中还提供了ALPHA函数,平时困扰我们的很多Domain里带有转换ROUTINE的字段,都可以通过此函数解决。
还有,让人值得高兴的时,很多之前在ABAP中只能通过函数来计算的,现在也都有了基本的内置函数,比如日期和时间戳的转换。这些内置函数合理的搭配使用,还是可以做不少事情的。
但内置函数还没到特别灵活的地步,一般参数只支持直接输入,不能再嵌套简单的表达式。比如,我们最常用的合计功能,很多财务数据都是利用一个借贷标识S/H,和一个正的金额来存储数据。当我们要合计这些数据时,没法直接将正负先计算好,再用SUM合计。这时,我们需要先做一个基础的CDS View,将正负根据借贷标识计算好,再用另一个CDS View来取数。有时复杂点的场景甚至要嵌套三层以上。这点暂时没有太好的解决办法。
丰富的内置函数无疑是要慢慢学习的,可以先大概看一下都有哪些,用的时候再来查详细语法:
除上述示例中看到的,CDS还有如下功能:
6. ODATA的发布
这点是通过上面提到的Annotation(@OData.publish: true)实现的,这也使得它可以和Fiori很好的集成。
可以参考以下Help文档:
7. 权限控制
传统的ABAP开发,会针对Tcode,或代码里的AUHOURITY-CHECK语句等方式对权限进行控制,但这时数据实际已经到了应用层,只是对用户实现了权限控制。CDS View,提供了DCL(Data Control Language)语句。这使得权限控制可以直接内置在SQL语句中,在ABAP层,再配合SU21等权限对象的配置来实现。
可以通过下面博客中的例子更直观了解:
https://blogs.sap.com/2017/02/27/abap-cds-views-with-authorization-based-on-access-control/
考虑到CDS View的复用性,参数传递功能肯定是不可少,这点对限制从数据库抽取数据的量,也有很大帮助。参数根据可见性分为两种:一种是可见的,比如传入一个公司代码在WHERE条件中使用;另一种是隐藏的,一般在暴露OData时使用,不用显式地传递,比如执行时直接使用系统登录用户作为值。不过第二种现在也仅仅支持五个,分别对应ABAP工作台中的:SY-MANDT、SY-LANGU、SY-UNAME、SY-DATUM、SY-UZEIT。
可以参考以下Help文档:
https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.52.2/en-US/97c5057a2302453b97e19641b0d8cbc7.html
9. 扩展性
AMDP实际上提供了一种让你直接调用HANA数据库中SQL Script的功能,类似于Native SQL,让你可以做的事更多,尤其在Open SQL不够用的时候。举个例子,比如两套独立系统,底层用的是同一套HANA数据库,只是数据分成了不同的Schema。现在系统A由于业务需求,希望防范系统B中的数据。你第一想到的是不是通过接口来实现?有了AMDP,因为它执行的是HANA数据库的SQL Script,通过简单的配置,就可以直接跨系统访问数据,甚至两个系统的表都可以做Join。
技术原理上实际非常简单,系统留了一个接口IF_AMDP_MARKER_HDB,你只需要创建一个类来实施它。将你的SQL Script写在这个类的某个方法中,需要的时候调用它就可以了。
看到这是不是发现和CDS View没啥关系,技术上来说确实没啥直接关系,只不过两者经常结合使用,所以在此提及。
AMDP的功能细节比较多,可以查看Help文档学习:
11. 其它
AS ABAP 7.53之后,还出现了CDS Hierarchy、Definition of Abstract CDS entity、Definition of Metadata Extensions等,因不太常用,可根据兴趣自行查询,这里只提及收录一下。
文章看到这,以上带数字编号标题的,都是在【概括CDS的特点及功能】下,了解完CDS View的这些特点及功能,下面我们回到High Level来讨论。
CDS View的优势是速度快吗?
那为什么还要使用CDS View呢?上面提到的丰富特性和功能,肯定是最重要的原因。还有一个重要的原因就是其复用性。举个简单的例子,如果一个需求是希望在某个表检索后,其中某个字段要经过简单的计算然后输出,并且这样的数据,在一个项目中的很多场景中都会用到。如果用传统ABAP,我们会先Open SQL取数,然后在LOOP中编辑,最后使用。如果使用CDS View,我们可以直接将这些都放在CDS Entity里,并且这个Entity是可以在SE11检索到,直接当做一个表来使用。还有,上面也提到,系统也从业务角度,创建了丰富的标准CDS Entity,我们如果熟悉了这些,也可以直接拿来使用,或者在其基础上定义我们自己需要的。
从辩证主义的角度,讲点劣势?
CDS View的使用肯定是个大趋势,S/4HANA底层很多数据建模也都已经替换成了CDS Entity。如果你去SE11看一些常用的业务表,很多都有替代对象,也就是说即使你用的是某个表,底层系统也会使用其替代对象。这样可以保持原有代码不用更改,可以无缝切换到新的建模。 但凡事都有利有弊。任何一项新技术的推出(其实已经不新了,国内的项目新技术总是用的晚几年,这样也好,有很多资料可以查),都会带来一些不便。比如,在项目实施和运维过程中,客户的很多开发资源,可能并没有接触过这个技术。如果整个项目在实施期间大量地采用这种方式,对于负责运维的同事,是个挑战。而且,传统项目的开发规范,基本只限制到了ABAP,对于新出现的CDS View,则没有太多限制,比如命名和整体的建模设计思路,这也会给之后的运维带来困难。 但技术就是在这样的情况下不断迭代的,SAP的车轮也会一直向前滚动。 最后,这篇文章的初衷是自己学习的一个总结,所有内容都在阅读了不同来源不同语言的资料后,通过自己的理解组织而成。希望它也同时可以给不同背景的读者一点帮助。 如果有意见建议,欢迎留言讨论,谢谢。