ABAP 内表的最佳实践

使用合适的内表类别

选择合适的表类别。对于小型表,索引或散列键可能是多余的,但对于大表,始终使用以下规则:

  • 索引访问:标准表
  • 索引访问和键访问:排序表
  • 只访问关键字:哈希表

特别是对于行数较多的表格,必须谨慎选择合适的表格类别。以下建议主要源自处理速度要求:

  • 标准表

如果主要访问类型是顺序处理或索引访问,则可以始终使用该表类别。填写标准表时,应使用 APPEND 添加行,其他访问则使用索引规范(相应语句的 INDEX 语句)。理想情况下,补充数据的过程应与其他访问数据进行分离。在进行显式排序后,还可以使用二进制搜索(BINARY SEARCH)来优化键访问(自由键),这样就可以为顺序处理(LOOP)等确定一个入口点。不过,由于采用线性搜索,如果内部表的主要访问类型是键访问,那么大型标准表(超过 100 行)就不适合作为表类。

  • 排序表

如果既需要快速键访问,又需要索引访问,还需要在填表时对行进行排序,那么这类表就很有用。此外,排序表还适用于 LOOP 循环中的部分顺序访问,其中在 WHERE 条件中指定了表键的第一部分。最后,在无法定义唯一键的情况下,具有模糊键的排序表是哈希表的唯一选择。

  • 哈希表

如果键访问是数据表的核心操作,那么这种表类就很有用。

选择适当的方式来访问表行

可以通过访问各个行(使用 READ TABLE 或表表达式)或按顺序(使用 LOOP AT)来读取内表。在这两种情况下,读取时可以通过三种方式存储内表的访问行:

  • INTO 将行复制到结构中
  • ASSIGNING 将行分配给字段符号,这使得可以直接寻址该行
  • REFERENCE INTO 创建对行的引用

表格表达式也是如此,只是根据结果的类别来选择行存储类型。

原则是:

  • 如果行类型较窄且不需修改读取的行,则使用工作区(结构)
  • 如果行类型为宽或深并且要修改读取的行,则使用字段符号
  • 如果行类型为宽或深并且要传递对读取行的引用,请使用引用

出于性能原因,最好避免循环中的行复制

细节

选择输出行为的标准一方面是处理速度,另一方面是要对读取行执行的操作:

  • 如果要修改读取行的内容,通常应使用添加 ASSIGNING 或(在表表达式的情况下)适当的结果。这允许使用值语义直接访问行,并且无需稍后进行 MODIFY 操作。
  • 如果需要对读取行的引用可以使用引用语义进行处理,则将使用添加 REFERENCE INTO 或(在表表达式的情况下)适当的结果。
  • 如果不修改读取行的内容,则可以使用这些过程中的任何一个。表的行类型对于性能非常重要。如果表行很宽或包含较深的组件(例如,字符串或其他表),则如果使用 ASSIGNINGREFERENCE INTO 而不是 INTO,读取通常会更快。它们的使用方式是选择使用两者中哪一个的决定因素。

当处理行平坦且占用空间不超过大约 1KB 的表时,使用 INTO 进行复制(至少对于 READ 语句而言)比配置动态访问所需的管理更快。对于语句 LOOP,这些成本仅产生一次,因此始终建议在一定数量的行以上使用 ASSIGNINGREFERENCE INTO。相反,如果要修改目标区域而不影响内部表,则应始终使用 INTO

不好的方式

以下源代码显示了将内表的行分配给工作区的目的,目的是修改读取的行。然而,对于此修改,需要附加语句 MODIFY,并且每次循环都会发生两个不必要的复制过程。

ABAP 复制代码
LOOP AT itab INTO wa.
   ...
   wa = ...
   MODIFY itab FROM wa.
ENDLOOP.

好的方式

以下源代码更正了上面的示例;这里,使用字段符号来直接访问以修改读取的行。不会产生不必要的复制成本。

ABAP 复制代码
LOOP AT itab ASSIGNING <fs>.
   ...
   <fs> = ...
ENDLOOP.

不要在循环中修改整个表

循环访问内表时,不要执行会修改整个表体的语句。仅逐行修改表。

除了用于编辑内表中各个行的语句之外,还可以使用其他语句来寻址和修改表的整个主体。例子:

  • 适用于整个内表的所有分配类别
  • 使用 CLEAR 或 FREE 删除整个内表
  • 目标范围内的操作,例如 SELECT INTO TABLE

您不能使用跨内部表的循环来执行对表的访问,从而一次性修改整个表主体。

对整个表体的修改访问通常会产生运行时错误,并且至少会产生不可预测的程序行为。如果可以静态检测到这一点,则当使用相关表操作时,类内以及具有可静态检测的辅助键的循环中也会发生语法错误。否则,出于兼容性原因,语法检查只会返回警告。

使用 RETURN 退出例程

仅使用 RETURN 退出方法、函数、表单等。不要使用 CHECKEXIT

不要在对话框模块和事件块中实现逻辑

相反,调用封装逻辑实现的相关类方法。

除了过程之外,还有两种类型的处理块。但是,它们没有参数接口,并且不允许声明本地数据:(AT SELECTION-SCREENGET 是例外,但不应被利用):

  • 对话模块:对话模块使用语句 MODULE 引入,并使用语句 ENDMODULE 结束。这些模块形成了经典 dynpro 和相关 ABAP 程序之间的功能接口。它们是从 dynpro 流逻辑内部调用的。
  • 事件块:事件块由相应的关键字引入,并由下一个处理块隐式结束。当相关事件发生时,ABAP 运行时环境会触发事件块的处理。

事件块用于:

  • 加载程序(LOAD-OF-PROGRAM)
  • 报告可执行程序(带逻辑数据库)处理过程中发生的事件(初始化、开始选择、获取、结束选择)
  • 选择屏幕事件(AT SELECTION-SCREEN ...)
  • 经典列表处理的列表事件(AT LINE-SELECTION、AT USER-COMMAND)

原则: 不要在对话框模块和事件块中实现逻辑

由于无法在对话框模块和事件块中声明本地数据,因此您无法实现任何有用的程序逻辑。因此,对话框模块和事件块------只要它们仍然是必要的------应该只包含一个方法调用。如果您一致使用 ABAP 对象,则仅需要以下元素:

  • 在使用类池以外的程序类型的情况下,将 LOAD-OF-PROGRAMINITIALIZATION 作为程序构造函数
  • 处理经典 dynpros 和选择屏幕时的对话框模块和 AT SELECTION-SCREEN
  • 用于后台处理的可执行程序中的 START-OF-SELECTION 为了提高可读性,您应该始终显式指定该语句(尽管在许多情况下它是可选的)
  • 尽管在语法上是可能的,但您不应在程序中多次指定事件块

Note:在函数组中使用 LOAD-OF-PROGRAM 基本上与在全局类中使用静态构造函数相同。在可执行程序中,如果需要评估使用 SUBMIT 传递的任何参数,则可以使用 INITIALIZATION 代替。

例子

以下源代码显示了包 SABAP_DEMOS_CAR_RENTAL_DYNPRO 中功能组 DEMO_CR_CAR_RENTAL_SCREENS 的 PAI 模块。可以使用事务 DEMO_CR_CAR_RENTAL 调用此包中的屏幕。这些对话框模块遵循上述规则。它们不包含自己的实现。他们调用函数组的本地类的方法。

ABAP 复制代码
MODULE cancel INPUT.
  screen_handler=>cancel( ).
ENDMODULE.

MODULE user_command_0100 INPUT.
  screen_handler=>user_command_0100( ).
ENDMODULE.

MODULE customers_mark INPUT.
  customer_table=>mark( ).
ENDMODULE.

MODULE reservations_mark INPUT.
  reservation_table=>mark( ).
ENDMODULE.

仅在特殊情况下使用宏

尽可能避免使用宏。宏有几个缺点:

  • 无法调试;
  • 没有语法检查;
  • 隐式调用接口;
  • 没有接口参数类型检查。

为隐式调用的消息创建锚点

当您隐式传递消息属性(类、数字、参数)时,例如通过函数或方法调用,或者使用变量,使用锚点让消息可以在使用位置列表中搜索。

可以通过以下方式完成(因为它是在标准中完成的):

ABAP 复制代码
IF 1 = 2. 
    MESSAGE i123(abc) ... . 
ENDIF.

或者:

scss 复制代码
MESSAGE i123(abc) ... INTO sy-msgli. "and then use sy-msg* fields to pass the message attributes
相关推荐
盛派网络小助手1 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
∝请叫*我简单先生1 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
zquwei2 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
dessler3 小时前
Docker-run命令详细讲解
linux·运维·后端·docker
Q_19284999063 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
ZSYP-S4 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
Yuan_o_4 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
程序员一诺5 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
DT辰白5 小时前
如何解决基于 Redis 的网关鉴权导致的 RESTful API 拦截问题?
后端·微服务·架构