关于 rap
面向 ABAP Cloud 事务应用开发的 RAP 实用指南,涵盖设计选择、分层实现、行为定义和 EML,并说明 clean core 限制。
主要功能
- 01RAP 流程与场景选择
- 02业务对象分层设计
- 03BDL 行为定义
- 04ABP 处理器与保存类指南
- 05EML 操作示例
- 06草稿与保存序列说明
适用场景
- 01设计新的托管或非托管 RAP 业务对象
- 02为业务对象添加操作、校验或判定
- 03使用 EML 消费 RAP 业务对象
- 04排查 RAP 实现问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ likweitan/ abap-skills --skill rap安装后在 Claude Code 中输入/rap确认已加载。
附带文件references/eml-quick-reference.md
详细介绍
RAP(RESTful ABAP Programming Model)
使用 ABAP RESTful Application Programming Model(RAP)在 ABAP Cloud 中构建事务型应用程序的指南。
Clean core 上下文:RAP 是 ABAP Cloud 开发的主要编程模型,其等级为 clean core Level A。面向 SAP Cloud ERP 核心范围的自定义 RAP Fiori 应用属于 Level A;通过已发布的扩展点扩展基于 RAP 的 SAP Fiori 应用,也属于 Level A。相比之下,基于 SEGW/BOPF/UI5 的应用及其扩展属于 Level B。请将 RAP 处理程序代码限制在已发布的 API 范围内,以保持在 Level A——只要调用一个内部对象,整个应用就会降级为 Level C。有关等级的详细信息,请参阅
abap-cloud技能。
工作流
-
确定用户的目标:
- 从头创建新的 RAP BO
- 为现有 BO 添加行为(操作、验证、确定)
- 编写 EML 语句以使用 RAP BO
- 排查 RAP 相关问题
- 了解 RAP 概念
-
识别场景:
- 托管(绿地)还是非托管(棕地)
- 是否启用草稿
- 编号概念:早期/后期、内部/外部/托管
- 单个实体还是组合树(根实体 + 子实体)
-
按照 RAP 分层架构指导实现:
- 数据建模(数据库表 → CDS 视图实体)
- 行为定义(使用 BDL 的 BDEF)
- 行为实现(ABAP 行为池)
- 业务服务公开(服务定义 → 服务绑定)
-
使用正确的 BDL 和 EML 语法提供代码示例
RAP 架构层
| 层 | 工件 | 用途 |
|---|---|---|
| 数据建模 | 数据库表、CDS 根视图实体/子视图实体 | 数据持久化和语义数据模型 |
| 行为定义 | BDEF(.bdef) | 使用 BDL 声明事务行为(操作、特征) |
| 行为实现 | ABAP 行为池(BP_*) | 在处理程序/保存器类中实现业务逻辑 |
| 投影 | CDS 投影视图、投影 BDEF | 为特定服务使用者调整 BO |
| 业务服务 | 服务定义、服务绑定 | 将 BO 公开为 OData 服务 |
实现类型
托管(绿地)
- 框架自动处理事务缓冲区和标准 CRUD 操作
- 只需为非标准操作(操作、验证、确定)编写自定义代码
- 自动处理保存(可通过
additional save增强,或替换为unmanaged save)
managed implementation in class zbp_r_entity unique;
strict ( 2 );
非托管(棕地)
- 开发者提供事务缓冲区并实现所有操作
- 用于需要将现有业务逻辑嵌入 RAP 的场景
unmanaged implementation in class zbp_r_entity unique;
strict ( 2 );
行为定义(BDL)快速参考
完整 BDEF 结构
managed implementation in class zbp_r_root unique;
strict ( 2 );
with draft;
define behavior for ZR_Root alias Root
persistent table zroot_tab
draft table zroot_d
etag master LocalLastChangedAt
lock master
total etag LastChangedAt
authorization master ( global )
late numbering
{
// Field characteristics
field ( readonly ) RootUUID, CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
field ( mandatory ) Description;
field ( numbering : managed ) RootUUID;
// Standard operations
create;
update;
delete;
// Association to child entity
association _Child { create; }
// Actions
action doSomething result [1] $self;
static action createFromTemplate parameter ZD_CreateParam result [1] $self;
internal action recalculate;
// Validations
validation validateDescription on save { create; field Description; }
// Determinations
determination setDefaults on modify { create; }
determination calcTotal on modify { field Quantity, Price; }
// Draft actions
draft action Resume;
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft determine action Prepare
{
validation validateDescription;
}
// Side effects
side effects
{
field Quantity affects field TotalAmount;
field Price affects field TotalAmount;
determine action Prepare executed on field Description affects messages;
}
// Events
event created;
event deleted parameter ZD_DeletedEvent;
// Mapping
mapping for zroot_tab corresponding
{
RootUUID = root_uuid;
Description = description;
}
}
define behavior for ZR_Child alias Child
persistent table zchild_tab
draft table zchild_d
etag master LocalLastChangedAt
lock dependent by _Root
authorization dependent by _Root
{
field ( readonly ) ChildUUID, RootUUID;
field ( numbering : managed ) ChildUUID;
update;
delete;
association _Root;
mapping for zchild_tab corresponding
{
ChildUUID = child_uuid;
RootUUID = root_uuid;
}
}
投影 BDEF
projection;
strict ( 2 );
use draft;
define behavior for ZC_Root alias Root
{
use create;
use update;
use delete;
use action doSomething;
use association _Child { create; }
}
define behavior for ZC_Child alias Child
{
use update;
use delete;
use association _Root;
}
BDL 核心元素
| 元素 | 语法 | 用途 |
|---|---|---|
| 托管编号 | field ( numbering : managed ) KeyField; | 框架自动分配 UUID 键 |
| 提前编号 | early numbering | 通过 FOR NUMBERING 处理器在交互阶段自定义键分配 |
| 延迟编号 | late numbering | 通过 saver 方法 adjust_numbers 在保存序列中分配键 |
| 锁定主实体 | lock master | 根实体控制悲观锁定 |
| 锁定从属实体 | lock dependent by _Assoc | 子实体将锁定委托给父实体 |
| ETag | etag master FieldName | 乐观并发控制 |
| 总 ETag | total etag FieldName | 启用草稿的 BO 必需 |
| 草稿 | with draft; | 为整个 BO 启用草稿处理 |
| 协作式草稿 | with collaborative draft; | 多用户草稿编辑 |
| 严格模式 | strict ( 2 ); | 启用额外的 BDL 语法检查(使用最新版本) |
ABAP 行为池(ABP)
处理器类
CLASS lhc_root DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
" Standard operations (unmanaged only)
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE Root.
" Action implementation
METHODS doSomething FOR MODIFY
IMPORTING keys FOR ACTION Root~doSomething RESULT result.
" Validation
METHODS validateDescription FOR VALIDATE ON SAVE
IMPORTING keys FOR Root~validateDescription.
" Determination
METHODS setDefaults FOR DETERMINE ON MODIFY
IMPORTING keys FOR Root~setDefaults.
" Instance feature control
METHODS get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Root RESULT result.
" Instance authorization
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Root RESULT result.
ENDCLASS.
CLASS lhc_root IMPLEMENTATION.
METHOD doSomething.
" Read current instance data
READ ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(entities)
FAILED failed.
" Modify instances
MODIFY ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
UPDATE FIELDS ( Status )
WITH VALUE #( FOR entity IN entities
( %tky = entity-%tky
Status = 'DONE'
%control-Status = if_abap_behv=>mk-on ) )
FAILED failed
REPORTED reported.
" Fill result
result = VALUE #( FOR entity IN entities
( %tky = entity-%tky
%param = entity ) ).
ENDMETHOD.
METHOD validateDescription.
READ ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
FIELDS ( Description ) WITH CORRESPONDING #( keys )
RESULT DATA(entities).
LOOP AT entities INTO DATA(entity).
IF entity-Description IS INITIAL.
APPEND VALUE #( %tky = entity-%tky ) TO failed-root.
APPEND VALUE #( %tky = entity-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Description must not be empty' )
%element-Description = if_abap_behv=>mk-on
) TO reported-root.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setDefaults.
READ ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(entities).
MODIFY ENTITIES OF zr_root IN LOCAL MODE
ENTITY Root
UPDATE FIELDS ( Status CreatedAt )
WITH VALUE #( FOR entity IN entities
( %tky = entity-%tky
Status = 'NEW'
%control-Status = if_abap_behv=>mk-on ) )
REPORTED reported.
ENDMETHOD.
ENDCLASS.
Saver 类
CLASS lsc_root DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS save_modified REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
CLASS lsc_root IMPLEMENTATION.
METHOD finalize.
" Final calculations before save
ENDMETHOD.
METHOD check_before_save.
" Final consistency checks
ENDMETHOD.
METHOD save_modified.
" Only needed for 'with additional save' or 'with unmanaged save'
" Raise business events here
IF create-root IS NOT INITIAL.
RAISE ENTITY EVENT zr_root~created
FROM VALUE #( FOR <cr> IN create-root
( %key = VALUE #( RootUUID = <cr>-RootUUID ) ) ).
ENDIF.
ENDMETHOD.
METHOD cleanup.
" Clear transactional buffer
ENDMETHOD.
METHOD cleanup_finalize.
" Rollback finalize changes on failure
ENDMETHOD.
ENDCLASS.
EML(实体操作语言)速查
EML 是用于以编程方式与 RAP BO 交互的 ABAP 语言。主要操作:MODIFY ENTITY(创建/更新/删除/执行操作)、READ ENTITIES、COMMIT ENTITIES、ROLLBACK ENTITIES。
- 创建:
MODIFY ENTITY ... CREATE FIELDS ( ... ) WITH VALUE #( ( %cid = '...' ... ) ) - 读取:
READ ENTITIES OF ... ALL FIELDS WITH VALUE #( ( key = val ) ) RESULT DATA(result) - 更新:
MODIFY ENTITY ... UPDATE FIELDS ( ... ) WITH VALUE #( ( %tky = ... ) ) - 删除:
MODIFY ENTITY ... DELETE FROM VALUE #( ( %tky = ... ) ) - 执行操作:
MODIFY ENTITY ... EXECUTE actionName FROM VALUE #( ( %tky = ... ) ) - 深度创建:使用
CREATE BY \_Assoc,并搭配%cid_ref和%target
有关包含代码示例的完整 EML 语法,请阅读 references/eml-quick-reference.md。
草稿处理
- 在 BDEF 标头中通过
with draft;启用 - 每个实体都需要单独的
draft table - 草稿表必须包含
"%admin": include sych_bdl_draft_admin_inc; - 草稿操作(
Edit、Activate、Discard、Resume、Prepare)会隐式提供 - 使用
%is_draft组件(或包含该组件的%tky)区分草稿实例和活动实例
RAP 保存序列
| 阶段 | 调用的方法 | 用途 |
|---|---|---|
| 提前保存 | finalize → check_before_save →(失败时:cleanup_finalize) | 确保数据一致性 |
| 延迟保存 | adjust_numbers → save / save_modified → cleanup | 将数据持久化到数据库 |
- 提前保存失败(sy-subrc = 4)时会返回交互阶段
- 延迟保存是不可逆点——要么提交成功,要么发生运行时错误
BDEF 派生类型的关键组件
| 组件 | 用途 |
|---|---|
%cid | 内容 ID — 新实例的唯一初步标识符 |
%cid_ref | 对同一 EML 请求中 %cid 的引用 |
%key | 主键字段 |
%tky | 事务键(%key + %is_draft + %pid)— 推荐 |
%data | 所有键字段和数据字段 |
%control | 指示提供了哪些字段/请求了哪些字段的标志 |
%is_draft | 草稿标志(仅适用于启用草稿的 BO) |
%pid | 初步 ID(仅适用于后期编号) |
%target | 用于通过关联创建的目标实例 |
%param | 操作/函数参数值 |
最佳实践
- 新建 BO 时始终使用
strict ( 2 ); - 优先使用
%tky而非%key,以确保代码面向未来(可处理草稿/后期编号转换) - 即使之后不引用,也始终在创建操作中填写
%cid - 在处理程序方法中使用
IN LOCAL MODE,以绕过功能控制和授权检查 - 实现用于数据一致性检查的验证,以及用于计算字段的确定逻辑
- 让处理程序方法专注于特定任务;使用 ABP 辅助类共享逻辑
- 对于托管 BO,仅为非标准操作实现处理程序方法
参考资料
RAP 的 Clean Core 级别说明
| 场景 | 级别 | 说明 |
|---|---|---|
| 面向核心范围的自定义 RAP Fiori 应用 | A | 新应用的目标状态 |
| 通过已发布扩展点扩展基于 RAP 的 SAP Fiori 应用 | A | 首选的扩展方式 |
| 仅使用已发布 CDS 视图和已发布 API 的 RAP BO | A | 处理程序/保存程序代码仅限使用已发布的 API |
使用经典 API(transactional-consistent)的 RAP BO | B | 只有标记为 transactional-consistent 的经典 API 才能安全地用于 RAP |
| 使用内部对象或直接读取表的 RAP BO | C | 封装该对象并创建单个 ATC 豁免 |
| 自定义 SEGW/BOPF/UI5 应用 | B | 优先使用 RAP;例外情况可能涉及专业知识或复用 |
| 扩展 SEGW/BOPF/UI5 Fiori 应用 | B | 提供 RAP 应用后迁移至该应用 |
基于 SE54 的 BC UI | B | 优先使用基于 RAP 的业务配置应用 |
关键规则:只有当经典 API 在 Cloudification Repository 中带有 transactional-consistent 标签时,才能在 RAP 应用中使用。其他经典 API 可能会破坏 RAP 的事务模型。
相关技能
- cds-view-entities:用于建立 RAP 业务对象的基础数据模型
- abap-sql-amdp:用于在 RAP 中实现复杂的数据库操作
- authorization-iam:用于实现 RAP 授权检查
- odata:用于将 RAP 业务对象公开为 OData 服务
- rap-business-events:用于在 RAP 中实现事件驱动模式
- abap-cloud:用于划分 Clean Core 级别并实现包装器模式
- badi-enhancement:用于实现已发布的 RAP BAdI,以扩展标准 RAP BO