7.2 怎么加注释
首先要看懂注释,comparefilter 一般都是true,这样在association 里的join只被验证一次,如果是FALSE就会不停的被验证。
preservekey, 验证和数据库表的key是否一致。
authorizationcheck, 需要验证权限。不过我们没有设access control,所以只有个warning。
我们可以加view注释:
basic表示这个view是直接建在数据库表上的。
再来加元素注释:
比如对于值字段,要加个单位的:
在单位上添加注释:true,在值上面添加注释,要把单位的别名加上。
@semantics.quantity.unitOfMeasure:'OrderUnit'
menge as OrderQuantity,
@Sementics.unitOfMeasure: true
meins as OrderUnit
扩展注释:
@OData.publish: true
这个要发布起来还是挺复杂的。UI5可用。要启用服务。
要到GUI里面。/iwfnd/maint_service里配置。
8. Union 和 Join
8.1 Union
Union要求两个表的字段数相同,字段名匹配,顺序一致。
如果两个union的view还有association的话,那底层的association和基数以及对应的目标表都得一致才行。
define view ... as
select
from demo_1
{a as ch1, b as ch2, c as ch3}
union
select
from demo_2
{d as ch1, f as ch2, g as ch3}
对于Union来讲,两个表中的重复项会被消除。
Union All才不会消除重复项。
8.2 Join(inner/left outer/right outer/cross)
两表字段不同。
define view zdemoJoin as select from ekpo as po
inner join eban as pr
on po.banfn = pr.banfn
and po.bnfpo = pr.bnfpo {
po.ebeln as PN,
po.matnr as Matrial,
pr.banfn as PRnum
}
8.3 association 关联
建模CDS view之间的关系的。
define view ZI_PO
as select from ekko
association [0..*] to ZI_PU as _PU on $projection.PurchaseOrder = _PU.PurchaseOrder
{ key ebelen as POrder,
bsart as ordertype,
@objectModel.association.type :[#TO_COMPOSITION_CHILD]
—PU
}
关键词 association
基数[0..*]可以有0或者无穷个对应。关联到另一个CDS view上,然后得给一个别名,以下划线开头的。
同时这个被关联的CDS view的值可以直接发布到现有的CDS view下面。
基数的关联关系,如下图所示。1 表示最少有0条,最多有1条对应。
[1] | 0 | 1 |
[0..1] | 0 | 1 |
[1..1] | 1 | 1 |
[0..*] | 0 | 不限 |
[1..*] | 1 | 不限 |
0 | 1 |
那么association和join的区别是什么?
这个其实有点像HANA里面的refrential join。
在左外连接中:
我需要关联左右两个表。但是其实我只关心左表的数据。右表我要连接,但是我不关心它的数据。这时候,如果把数据都拿过来,其实是耗费性能的一件事。
那么我就用association。
join会去把所有的数据选出来,展示出来。但是association你得点击了才去选,而且只选一条。而且association要填基数。这点需要你了解表关系。
9. 货币和单位转换
9.1 变量
系统提供很多变量,比如$Session.user 就是sy-uname,系统当前用户名。
$Session.client就是sy-mandt。当前client。
$Session.system_date这个很有用 sy-datum
$Session.system_language sy-langu
define view ZI_PO
as select from ekko
association [0..*] to ZI_PU as _PU on $projection.PurchaseOrder = _PU.PurchaseOrder
{ key ebelen as POrder,
bsart as ordertype,
@objectModel.association.type :[#TO_COMPOSITION_CHILD]
—PU
}
where enarm = $Session.user
9.2 货币、单位转换
直接在数据库层级进行单位的转换。这些功能怎么实现的呢?
货币转换就是把一种货币金额转换为另一种货币金额。从美元转人民币啥的。
货币转换的function有四个强制参数和6个可选参数。
amount | * | CURR |
source_currency | * | CUKY |
target_currency | * | CUKY |
exchange_rate_date | * | DATS |
exchange_rate_type | OP | CHAR 4 |
client | * OP | CLNT |
round | OP | CHAR |
decimal_shift | OP | CHAR |
decimal_shift | OP | CHAR |
error_handling | OP | CHAR 20 |
define view zi_pr_quan_conv
with parameters p_DispCurr : waers_curc
as select from eban
{
key banfn,
key bnfpo,
@semantics.amount.currencycode: 'TransCurrency'
preis,
@semantics.currencycode: true
waers as TransCurrency,
badat as ReqDate,
@Semantics.amount.currencyCode: 'DisplayCurr'
currency_conversion ( amount => preis,
source_currency => waers,
target_currency => :p_DispCurr,
exchange_rate_date => badat
)
as DispAmount,
@Semantics.currencyCode: true
:p_DispCurr as DisplayCurr
}
单位转换就比如从KG转到磅重。有三个强制参数。
quantity | * | QUAN,DEX,INT1,INT2,INT4,FLTP |
source_unit | * | UNIT |
target_unit | * | UNIT |
client | OP | CLNT |
error_handling | OP | CHAR 20 |
define view ZI_POHeader
as select from ekko
association [0..*] to ZI_POItem as _POItem on $projection.PurchaseOrder = _POItem.PurchaseOrder
association [1..1] to ZO_POCus as _POCus on $projection.Supplier = _POCus.Supplier
{
key ebeln as PurchaseOrder,
case (bsart)
when 'RQ' then 'external'
when 'UB' then 'Stock'
else 'other'
end as PurOrderType,
ekorg as Purorg,
_POCus.SupplierName as SupplierName,
aedat as Creatdate,
waers as DocCur,
rlwrt as Totalval,
currency_conversion (amount => rlwrt,
source_currency => wares,
target_currency => cast('CNY' as waers),
exchange_rate_date =>aedat ) as Totalcnyvalue,
}
10. Client的处理
@CLientHandling 可以选择处理特定client的数据。
select * from ZPO
client specified
into table It_PO where client = '010'
用clientHandling也是一样的:有两个注释可以用。
type有三个值可以用。
继承就是说从数据源来说明client的相关与否。如果view里面用到的数据源(即使只有一个)是基于client相关的。那么这个view就是client dependent的。如果view里面的所有数据源都是与client不相关的,那它就是client_independent .
@ClientHandling.type: #INHERITED |
#CLIENT_DEPENDENT |
#CLIENT_INDEPENDENT
@ClientHandling.algorithm #AUTOMATED |
#SESSION_VARIABLE |#NONE
algorithm里面就要说明从哪个client来的了,怎么去取数据了。
如果值为#AUTOMATED,view的On 条件和其他语句都会被底层数据源的client列隐式的扩展。
如果是#SESSION_VARIABLE,我们有一个session 变量$Session.client也是会被隐藏式的加到where条件里,会自动选变量$Session.client的值,这个和#AUTOMATED有点像,但是性能会更好。因为其实你是写出来了这个where语句了。或者你可以用USING CLIENT这个语句明写出来。
#NONE这个是专门给非client相关的view用的,是默认CLIENT_INDEPENDENT的算法值。
举例: 一个采购订单和采购订单行项目的CDS view是client相关的,因为它用的底层的表是client相关的。那我们就可以在这个CDS VIEW里加两个注释:加到define view之前。
1) @ClientHandling.type: #INHERITED
2) @ClientHandling.algorithm #AUTOMATED
11. Access Control
对于权限控制来讲,就是说你要有应用的权限和数据的权限。
在ABAP里权限设置的语句如下:
loop at lt_podata into ls_podata.
authority-
check object 'M_BEST_EKO' "基于采购组织来定权限
ID 'ACTVT' FIELD '03'
ID 'EKORG' FIELD ls_podata-ekorg.
IF sy-subrc = 0.
"执行逻辑
ENDIF.
endloop。
在CDS view里的权限设置如下:一般role和cdsview应该有一样的名字。不过也可以不一样。
@MappingRole: true是默认把这个role给所有用户。
是用aspect pfcg_auth 条件可以用直接使用ABAP里面的权限字段。
@EndUserText.label : 'PO Access Control'
@MappingRole: true
define role ZI_POHDR
{ grant
select
on ZI_PUOrder
where (PurOrganization ) ?= aspect pfcg_auth( M_BEST_EKO, EKORG, actvt = '03');
}
如果不用aspect,也可以指定一些字段:
grant
select
on
ZI_PURODER
where PurOrganizaion = '0010' ;
设置好了之后,CDS抬头有个注释:@AccessControl.authozationcheck: #CHECK(默认是这个)
这就说明需要检查权限。
当然,除了#CHECK,还有#NOT_REQUIRED(有权限就检查,没有就不检查)和#NOT_ALLOWED ( 不执行权限检查)
这个是根据你PFCG里面的权限对象来搞的。去到这个权限对象里面能看到权限字段是哪些。这个例子里面是有两个权限对象ACTVT和EKORG。
激活这个DCL role之后,再跑CDS view就会被限制了。
11.1 层级CDS view及其对应的access control
当选择view a的数据,显然会对应到Role_a的管控:
select * from view_a into table @data(lt_view_a)
如果我选择view_b的数据,那么因为view_b的数据从view_a来的。
select * from view_b into table @data(lt_view_b) 这里也是只有role_b会被用到。
但是如果说我想让role_b去集成role_a怎么搞?下面就是role_b有自己的权限限制,同时继承了role_a。
@MappingRole:true
define role Role_b
{
grant selection view_b
where PurOr = '0001'
and inheriting conditions from entity Role_a;
}
实际情况下会有很多的CDS view从其他的view拿数据,同时拿完后还会和其他的view join.
这时候如果去写权限,会很麻烦,因为可能拿不到你想要的数据,数据在上层被限制住了。
这时候 可以去SACMSEL去执行 CDS Access Control Runtime Simulator。去测试用户权限。
12. VDM Virtual Data Model
一般情况下,咱知道,数据都是存储在数据库表中的。数据库表有一个非常复杂的结构。一般咱都是不明白这个表中到底存的是什么乱七八糟的数据,得有个专家帮你解释才行。
作为一个技术顾问,你得花点力气才能知道数据存在那里,怎么存的,存的什么数据。
为了解决这个问题呢,就搞了个Virtual Data Model。
其实也就是个CDS view,和其中的数据。VDM构建了一个中心数据模型。以前要到各个表里面去看数据,不过现在从CDS view里能看到数据是怎么关联的。
因为现在有了这个association
同时也可以给一些字段别名,这样你就能很清楚知道里面是什么数据了。
讲到这,好像也不知道VDM的结构是啥样。
这个不就是BW里面的概念么Composite provider。
对于其他的字段,最好也有命名方式。
来总结一下以上所有:
13. 扩展CDS VIEW
14. AMDP
以一个class的模板创建了一个可以用SQL来实现的在HANA数据库上的database procedure的AMDP方法。
当这个AMDP方法被调用的时候,一个database procedure就在HANA DB上生成了。
整个流程就是:
当这个存储过程建立了。其实也就是说这个AMDP方法可以被其他程序调用的。但是限制是什么呢?
1. SQL 语句集成到ABAP语法检查中
2. SQL debug也集成到ABAP debug中
3. 存储过程自动建在HANA 数据库中,不用delivery units去做生命周期管理
CLASS amdp_class DEFINITION。
PUBLIC SECTION.
*Marker interface with SAP HANA DB as database
INTERFACES IF_AMDP_MARKER_DB_TYPE.
METHODS amdp_method.
ENDCLASS.
CLASS amdp_class IMPLEMENTATION.
*AMDP method
METHOD amdp_method BY DATABASE PROCEDURE
FOR db_type
LANGUAGE db_language
OPTIONS db_options
USING db_entity.
ENDMETHOD.
ENDCLASS.
创建一个program来调用这个方法:
15. oData Services和 UI5 (Smart Template)