一、什么是 EML
EML(Entity Manipulation Language,实体操作语言) 是 ABAP 语言的一个子集,专门用于访问和操作 RAP(RESTful ABAP Programming Model)业务对象(Business Object,简称 BO)。
官方对 EML 的定义非常克制:它不是一门新语言,也不是 Open SQL 的别名,而是在 ABAP 体系中新增的一组语法结构,用于在 ABAP 代码中直接与 RAP BO 交互。
二、EML 在 RAP 生态中的定位
┌─────────────────────────────────────────────────────┐
│ RAP 应用层 │
├─────────────────────────────────────────────────────┤
│ Fiori UI │ OData API │ ABAP Report │ BAdI │
└─────┬──────┴──────┬──────┴───────┬────────┴─────┬────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────┐
│ EML 入口 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────┐ │
│ │ READ │ │ CREATE │ │ UPDATE │ │DELETE│ │
│ └─────────┘ └─────────┘ └─────────┘ └──────┘ │
└─────────────────────┬───────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ RAP 业务对象 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ CDS 数据模型 │ │ Behavior定义 │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘
EML 是 RAP 业务对象的唯一 ABAP 访问入口,主要有以下两层定位:
1. 面向业务实体的访问语言
传统 ABAP 开发中,读写数据需要直接编写 SQL 语句操作数据库表。EML 则面向 RAP 中定义的业务实体(Entity),开发者只需要知道实体名称和字段,不需要关心底层表结构。所有访问都通过 RAP BO 接口进行,会自动触发 BO 中定义的校验逻辑、权限控制和行为实现。
2. RAP BO 的通用消费接口
EML 可以在任意 ABAP 程序中使用,包括 Report、BAdI 实现类,以及 RAP BO 自身的行为实现类。无论是消费一个已经发布的 RAP BO,还是在行为池内部操作自己的 BO,都使用同一套 EML 语法。
三、EML 核心语法实操
EML 提供两种核心语法结构:READ ENTITIES 用于读取数据,MODIFY ENTITIES 用于修改数据(包含 CUD 及 Action 执行)。创建类,类实现接口**if_oo_adt_classrun**

3.1 READ ENTITIES
READ ENTITIES OF root_entity
ENTITY entity_name
FIELDS ( field1 field2 ... )
FROM VALUE #( ( key1 = ... key2 = ... ) )
RESULT DATA(lt_result)
FAILED DATA(lt_failed)
REPORTED DATA(lt_reported).
| 语法组件 | 说明 |
|---|---|
FIELDS |
指定需要读取的字段列表(可选,不写则读取所有字段) |
FROM |
提供主键值,定位要读取的实例 |
RESULT |
存放读取结果的内部表 |
FAILED |
存放读取失败的实例键值 |
REPORTED |
存放读取过程中产生的消息 |
常见读取方式:
-
按主键读取 :FROM
VALUE #( ( %key = ... ) ) -
读取全部实例 :
ALL FIELDS WITH CORRESPONDING #( empty_table ) -
关联读取(READ BY ASSOCIATION):从主实体导航到子实体
案例:

3.2 MODIFY ENTITIES
MODIFY ENTITIES OF root_entity
ENTITY entity_name
CREATE | UPDATE | DELETE | EXECUTE
[IN LOCAL MODE]
WITH VALUE #( ... )
FAILED DATA(lt_failed)
REPORTED DATA(lt_reported)
MAPPED DATA(lt_mapped).
核心修饰符 IN LOCAL MODE:
| 使用场景 | 说明 |
|---|---|
| Develop 场景(BO 行为池内) | 可在 EML 语句后加 IN LOCAL MODE,绕过访问控制、授权检查和特征实例控制 |
| Consume 场景(消费其他 BO) | 不可加 IN LOCAL MODE,必须走标准权限校验 |
| Test 场景(单元测试) | 推荐不加,保持与真实消费行为一致 |
案例:
CLASS zcl_rap_eml_kj DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_rap_eml_kj IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
READ ENTITIES OF ZI_RAP_ATRAV_KJ
ENTITY travel
FROM VALUE #( ( TravelUUID = '007F6D70806C92DE1900C75A3D45A812' ) )
RESULT DATA(travels).
OUT->write( travels ).
OUT->write( 'UPDATE DONE' ).
MODIFY ENTITIES OF ZI_RAP_ATRAV_KJ
ENTITY travel
UPDATE SET FIELDS WITH VALUE #( ( TravelUUID = '007F6D70806C92DE1900C75A3D45A812'
Description = 'I like RAP@openSAP' ) )
FAILED DATA(failed)
REPORTED DATA(reported).
COMMIT ENTITIES RESPONSE OF ZI_RAP_ATRAV_KJ
FAILED DATA(failed_commit)
REPORTED DATA(reported_commit).
ENDMETHOD.
ENDCLASS.
保存激活后,数据预览:

3.3 CREATE ENTITIES
新实体的创建通过带有**CREATE** 子句的**MODIFY** 语句执行。对于创建实例的操作,会返回一个**mapped**表,该表将创建的实例映射到提供的内容ID。
CLASS zcl_rap_eml_kj DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_rap_eml_kj IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
" step 7 - MODIFY Create
MODIFY ENTITIES OF ZI_RAP_ATRAV_KJ
ENTITY travel
CREATE
SET FIELDS WITH VALUE
#( ( %cid = 'MyContentID_1'
AgencyID = '70012'
CustomerID = '14'
BeginDate = cl_abap_context_info=>get_system_date( )
EndDate = cl_abap_context_info=>get_system_date( ) + 10
Description = 'I like RAP@openSAP' ) )
MAPPED DATA(mapped)
FAILED DATA(failed)
REPORTED DATA(reported).
out->write( mapped-travel ).
COMMIT ENTITIES
RESPONSE OF ZI_RAP_ATRAV_KJ
FAILED DATA(failed_commit)
REPORTED DATA(reported_commit).
out->write( 'Create done' ).
ENDMETHOD.
ENDCLASS.

数据预览:

3.4 DELETE ENTITIES
测试代码:
CLASS zcl_rap_eml_kj DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_rap_eml_kj IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
" step 8 - MODIFY Delete
MODIFY ENTITIES OF ZI_RAP_ATRAV_KJ
ENTITY travel
DELETE FROM
VALUE
#( ( TravelUUID = '6AD96431AFBE1FD1948FBAC7A12D8771' ) )
FAILED DATA(failed)
REPORTED DATA(reported).
COMMIT ENTITIES
RESPONSE OF ZI_RAP_ATRAV_KJ
FAILED DATA(failed_commit)
REPORTED DATA(reported_commit).
out->write( 'Delete done' ).
ENDMETHOD.
ENDCLASS.
数据预览:过滤器查找时不存在

四、三结构消息机制:FAILED / REPORTED / MAPPE
这是最容易被忽略且最容易出错的部分。每个 EML 语句基本都有这三个结构:
MODIFY ENTITIES ...
WITH lt_data
FAILED DATA(lt_failed) " 失败记录 —— 存不下去的那些行
REPORTED DATA(lt_reported) " 消息记录 —— 存不下的“理由”
MAPPED DATA(lt_mapped). " 映射记录 —— 存下去的“证据”
| 结构 | 作用 | 常见使用方式 |
|---|---|---|
| FAILED | 记录操作失败的实例 ,存放的是实例的键(通常是 %tky),用于跟踪哪些操作失败了 |
IF lt_failed IS NOT INITIAL. ROLLBACK ENTITIES. ENDIF. |
| REPORTED | 记录操作过程中产生的业务消息,每条消息可精确关联到实体、字段甚至具体实例 | APPEND VALUE #( %msg = new_message( ... ) ) TO lt_reported,或在 OData 中自动映射到 UI 消息区域 |
| MAPPED | 记录成功执行的实例的映射关系 ,尤其是 %cid 到实际持久化主键的映射 |
获取 %cid 对应的主键;在需要跨实体顺序操作时(先创建 A,再把 A 的键塞给 B)对 MAPPED 做判断 |
理解关键 :
FAILED告诉 RAP "哪些不行" ,REPORTED 告诉用户 "为什么不行" ,MAPPED 告诉框架 "新的键在哪里"。三个结构分工明确、缺一不可。、从 BOPF 到 RAP 的演进
总结
| 框架 | 推出平台 | 核心特征 |
|---|---|---|
| BOPF | ABAP Platform 7.5 及更早 | 面向 SAP NetWeaver On-Premise,配置复杂 |
| RAP + EML | SAP S/4HANA 1909 及 SAP BTP ABAP 环境 | 云原生设计,Behavior Definition + EML 语法声明式简化操作 |
EML 不是"多了几条语法"这么简单:它改变了 ABAP 开发者与业务数据交互的方式------从面向表、面向 SQL 转变成面向实体、面向业务模型,让代码更贴近业务语义,而非底层数据结构。