拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RAP应用中的Value Help、Additional Binding与Key隐藏实践

RAP应用中的Value Help、Additional Binding与Key隐藏实践 做RAPRestful ABAP Programming Model应用的时间久了你会发现一个特别有意思的现象开发者最纠结的往往不是底层数据模型怎么设计而是用户面对列表时的那一下操作体验。尤其是Value Help、Additional Binding和Key隐藏这三件事它们不解决能不能跑的问题却直接决定了应用好不好用。用户打开一张订单列表看到的是一串没有业务含义的UUID技术键搜索时只能对着业务单号干瞪眼——那这个应用无论底层多稳都会被吐槽反人类。这篇文章就围绕RAP应用里这套完整的打法展开怎么用Value Help把搜索做得顺手怎么用Additional Binding把F4选择后的附加字段带回来怎么把技术Key干净利落地藏到幕后以及这三者搭配时最容易踩的坑。1. 整体设计这三件事为什么必须放在一起打1.1 业务场景用户视角与技术视角的错位先说一个最常见的业务场景。假设你有一张自建订单表业务上每次搜索都要按客户编号或客户名称来定位但底层表的主键是一个UUID或者内部自增键。RAP建好之后OData服务默认会把这个技术主键暴露出来CDS视图里的每个字段也会原样呈现在Fiori界面上。代码写到这里问题就来了用户搜索时不知道UUID他们只记得这家客户叫某某公司用户就算通过F4找到了客户列表上也只能看到客户编号看不到客户名称信息量不够用户看到的那一列主键值毫无业务含义纯属视觉噪音。这三个问题恰恰对应了标题里的三件套Value Help负责帮用户找Additional Binding负责把找回来的相关信息带出来Key隐藏负责把技术键藏起来。它们不是三个孤立的功能而是同一条用户体验链路里的三个环节。1.2 三个手段的分工与配合关系用一句话概括它们的关系Value Help是入口Additional Binding是传输带Key隐藏是收尾。具体来说Value Help通过CDS注解给字段挂上F4帮助让用户可以按业务条件筛选、搜索、选择目标值Additional Binding用户在F4帮助里选择一条记录后除了选中的key字段本身搜索帮助视图里的其他字段比如客户名称、客户类型可以一并返回给主视图并在UI上展示Key隐藏主视图的字段通过UI注解隐藏用户看不到技术键但OData交互底层照样使用这个键完成读写。这三者的配合逻辑是Value Help让用户不直接面对key而是通过业务字段找到记录Additional Binding让这个过程中涉及的非key信息能完整传回Key隐藏则保证即便在最终展示层key也不会成为打扰用户的元素。我在实际项目里的经验是这套组合越早设计越好等Fiori界面都搭完了再补要么改的东西多要么容易出风格不一致的问题。2. Value Help让找数据这件事变得顺手2.1 CDS方式的搜索帮助View定义在RAP里实现Value Help最标准也最省事的路径是基于CDS视图的搜索帮助。它的原理是单独建一个CDS投影或查询视图专门作为某个字段的候选值来源然后在主视图里用Consumption.valueHelpDefinition注解把这个搜索帮助视图挂上去。我现在以一个订单场景为例完整走一遍。先有一个客户主数据视图作为搜索帮助的底层来源EndUserText.label: 客户搜索帮助视图 ObjectModel.search.result: true define view entity ZC_CUSTOMER_SEARCHHELP as select from zcustomer { key customer_id as CustomerId, customer_name as CustomerName, customer_type as CustomerType }这个视图不需要join多余的表它只需要把搜索所需的最小字段集暴露出来。注意几个关键点必须有key字段value help的返回就是以这个key为准的ObjectModel.search.result: true声明这是一个可搜索的查询视图便于后续在F4里做文本搜索字段的element类型必须与主视图对应的element一致类型不一致F4会直接不触发。很多新手在这里卡住的第一道坎就是element类型不匹配。比如主视图的CustomerId是CHAR(10)搜索帮助视图却定义成了NUMC(10)那OData服务在判断值帮助适用性时就会直接绕开F4按钮根本不会出现。2.2 在主View挂上Value Help注解搜索帮助视图建好之后回到主视图比如订单根视图ZC_ORDER在目标字段上加注解EndUserText.label: 订单根视图 Consumption.valueHelpDefinition: [ { entity: { name: ZC_CUSTOMER_SEARCHHELP, element: CustomerId }, additionalBinding: [ { element: CustomerName }, { element: CustomerType } ] } ] define root view entity ZC_ORDER as select from zorder as o { key o.order_uuid as OrderUUID, o.order_id as OrderId, o.customer_id as CustomerId, o.customer_name as CustomerName, o.customer_type as CustomerType, o.created_at as CreatedAt }这里entity指向搜索帮助视图element指明这个值帮助是针对CustomerId字段的。additionalBinding则是预告当用户选中某个客户时除了填回CustomerId还需要把CustomerName和CustomerType一并带回来。注意这里有一个容易混淆的点CDS注解层面的additionalBinding只是告诉元数据我希望带回来这些字段但运行时的OData响应中能否真的出现这些字段还要看行为定义里的声明。这就是下一节要展开讲的Additional Binding。先记着这个配合关系后面会串联起来。如果有多个字段需要值帮助可以重复使用Consumption.valueHelpDefinition比如在CustomerType上也挂一个类型翻译的搜索帮助做法完全一样。2.3 搜索筛选的配套设置Value Help只是搜索体验的一部分。在Fiori Elements列表页里筛选条上出现哪些字段、以什么顺序出现由Consumption.filter注解控制Consumption.filter: { position: 10 } OrderId; Consumption.filter: { position: 20 } CustomerId;这样用户在列表页的筛选条里可以直接按订单号、客户编号过滤。配合Consumption.valueHelpDefinition当用户点击筛选字段旁边的F4图标时就能进入搜索帮助界面。还有一个小技巧如果你希望某个字段支持模糊搜索可以在搜索帮助视图里给对应字段加上全文检索相关注解或者在搜索帮助视图里额外暴露一个名称搜索字段。实操中最常见的方式是让CustomerName同时出现在列表展示和搜索条件中Fiori会自动根据字段类型决定匹配方式。我还建议在元数据扩展里对搜索相关字段做分组展示UI.facet: [ { id: search, purpose: SEARCH, type: #FIELDGROUP_REFERENCE, position: 10 } ]让筛选条件在界面上有一个清晰的逻辑分区而不是散落在一堆字段里。这个细节平时没人提但验收的时候用户往往就在意这个。3. Additional Binding让F4选中的结果带得回来3.1 第一层CDS注解中的additionalBinding刚才在Consumption.valueHelpDefinition里已经看到了additionalBinding。这一层的核心作用定义值帮助选中后的字段映射关系。用户操作的时候流程是这样的在订单界面上点击CustomerId的F4帮助弹窗里显示的是搜索帮助视图客户编号、客户名称、客户类型用户选中一行点击确认系统把选中行的CustomerId回填到主视图的CustomerId字段同时根据additionalBinding定义把该行的CustomerName和CustomerType也带回给主视图的对应字段。这个过程在注解层面就声明完了。但请注意这一步本身只是元数据层面的声明并不会自动让这些字段出现在OData的响应报文里。如果行为定义里没有对应的声明前端拿到的JSON里依然不会有CustomerName。3.2 第二层BDEF中的with additional binding现在看行为定义。RAP是严格模式的任何一个非持久化字段要想出现在OData服务里都要在BDEF中显式声明。以我们订单根实体ZC_ORDER为例行为定义是这样的managed implementation in class zbp_order unique; strict ( 2 ); with draft; define behavior for ZC_ORDER alias Order persistent table zorder lock master authorization master ( instance ) etag master last_changed_at { field ( readonly : update ) OrderUUID, CreatedAt; field ( readonly ) CustomerName with additional binding; field ( readonly ) CustomerType with additional binding; create; update; delete; }关键就在这两行field ( readonly ) CustomerName with additional binding; field ( readonly ) CustomerType with additional binding;CustomerName和CustomerType在CDS主视图里存在但它们不是持久化字段或者来自关联、计算。为了让它们能作为响应字段返回给UI必须在BDEF中声明为with additional binding。加上readonly是因为这类字段是计算结果而非可编辑输入用户不应该改它。如果漏掉这一层声明表现会非常迷惑注解写了、F4也弹了、选择事件也触发了但前端始终拿不到回填后的名称字段列表一片空白。排查到最后发现问题不在UI和注解而在BDEF没认领这些字段。3.3 完整链路串联结合前面两部分Additional Binding的完整数据流是搜索帮助视图ZC_CUSTOMER_SEARCHHELP定义好候选值集合主视图的Consumption.valueHelpDefinition声明值与附加字段映射用户在F4选择一条记录OData服务执行选择逻辑回填主视图相关字段主视图字段通过BDEF的with additional binding声明进入响应结构Fiori前端拿到CustomerId、CustomerName、CustomerType分别渲染在不同的列或字段上。这就是为什么我说它是传输带——没有它Value Help选中的价值信息在到达UI之前就断了。还有一点值得注意with additional binding并不仅限于值帮助场景。如果你在CDS视图里通过join带出了供应商名称、物料描述希望在列表中只读展示同样可以在BDEF里这样声明不依赖F4也能生效。值帮助只是它最常见的业务触发场景之一。4. Key隐藏把技术主键请出用户视线4.1 UI层隐藏主键的做法技术主键在RAP里的作用毋庸置疑它负责唯一性识别、锁管理、ETag校验和OData的写回。但用户不需要看到它。隐藏主键最直接的方式是元数据扩展。给主视图单独建一个metadata extensionMetadata.layer: #CORE annotate view ZC_ORDER with { UI.hidden: true OrderUUID; UI: { lineItem: [{ position: 10, importance: #HIGH }], identification: [{ position: 10 }] } OrderId; UI: { lineItem: [{ position: 20, importance: #HIGH }], identification: [{ position: 20 }] } CustomerId; UI: { lineItem: [{ position: 30, importance: #HIGH }], identification: [{ position: 30 }] } CustomerName; }关键就是这一行UI.hidden: true OrderUUID;这样在Fiori Elements生成的列表、对象页、筛选条件里都不会出现OrderUUID。但OData服务内部的实体Key仍然存在编辑、删除、跳转详情页都没问题。4.2 隐藏后的写回与搜索行为隐藏Key之后用户进行编辑时前端提交的请求里依然会带上这个Key作为实体标识只是界面上不渲染而已。所以不用担心隐藏之后写操作会出问题。需要再补一刀的是如果你连业务键比如OrderId也想在创建时由系统自动生成那就要在行为定义的create相关操作里做号码分配逻辑。推荐使用determination在创建时刻给OrderId赋值determination on save { create SetOrderId; }同时配合一个好用的业务号生成函数或自定义编号范围。很多项目到最后才发现用户不想手工填单号这一块的规划应该在骨架阶段就定下来。至于搜索行为隐藏主键不影响任何搜索能力。用户通过筛选条、Value Help或全文检索定位记录底层都用不到UUID作为输入条件。这正好回扣了开头的核心诉求把key从用户视线里拿掉但把key的能力完整保留在系统内部。这里顺便说一个我在项目里反复验证过的经验技术键字段的命名尽量用UUID、InternalKey这类一看就知道是内部字段的名称不要叫OrderNumber之类的业务名。这样在隐藏、绑定、排查OData请求的时候很容易区分哪些是技术键、哪些是业务键不会产生混淆。5. 常见问题与排查实录5.1 问题速查表整套打法落地过程中下面这些问题是项目里的熟客先整理成一张速查表再挑三个最典型的展开聊。问题现象可能原因解决方向F4按钮不出现element类型不匹配valueHelpDefinition路径错误检查主视图与搜索帮助视图字段类型核对注解中的entity名称F4帮助弹出了但选择后附加字段没回填CDS注解缺少additionalBinding或BDEF缺少with additional binding补齐CDS注解和BDEF声明列表上客户名称列为空元数据扩展未标注该字段或BDEF未声明在metadata extension里给字段加UI配置主键字段在UI上可见元数据扩展未加UI.hidden添加隐藏注解创建时报主键缺失技术主键未自动生成确认DB字段使用UUID/GUID自动生成逻辑并检查CDS key映射搜索速度慢搜索帮助视图关联表过多、无索引精简搜索帮助视图字段给常用搜索字段建索引5.2 三个典型排查案例案例一F4按钮不出现排查半小时发现类型不匹配。当时主视图CustomerId是CHAR(10)搜索帮助视图里却写成了NUMC(10)。OData服务的值帮助匹配规则非常严格element类型不一致直接不挂。这个问题的求解路径很清晰把两边字段类型统一。但现实中很容易忽略因为CHAR(10)和NUMC(10)在数据库层看起来都是长度10的字段。案例二列表上取名拿不到值问题出在只做了CDS注解、没做BDEF声明。项目里同事给CustomerName加了additionalBinding但行为定义里没有field ( readonly ) CustomerName with additional binding;这一行。结果F4选择成功、字段也回填到了主视图但OData响应里根本没有CustomerName前端自然渲染不出来。补上BDEF声明后问题立刻消失。这个案例也说明CDS层的additionalBinding和BDEF层的with additional binding是两件事必须成对出现。案例三技术键隐藏后对象页跳转异常。隐藏OrderUUID之后列表页一切正常但列表行点击进入对象页时白屏。排查发现前端在跳转时依赖行绑定的OrderUUID作为导航Key虽然界面不显示这个字段但OData返回的JSON里必须有它。而我在BDEF里居然把这个字段从输出里漏掉了。这里的关键是UI.hidden只是隐藏显示不能把字段从服务输出里拿掉。解决办法是确保OrderUUID在CDS仍是key、在BDEF无附加限制同时元数据扩展只做隐藏、不做裁剪。还有一个老生常谈的注意点不要在隐藏Key的同时把标记为主键的字段从行为定义的字段列表里省略。RAP的运行时会依赖key完成锁管理和并发校验你只要把key暴露成readonly即可不要尝试彻底删除它。写在最后的一点经验这三件套实践下来我最大的感受是它们单拆开来都不难真正的复杂度在于彼此之间的配合——CDS注解、行为定义、元数据扩展三层需要同步改少一环都不行。建议在做这种改造时先在文档里把搜索帮助视图→主视图→BDEF→metadata extension这四个节点的对应关系列成一张表逐字段确认再到ABAP里动手。我在项目里吃过一次亏就是因为只在CDS注解里加了additionalBindingBDEF漏了结果上线前才暴露问题返工了一轮。把这套打法当作一个整体来规划而不是三个孤立的功能用户的搜索和键值体验才能真正顺手。
返回列表