SAP中的BRF+
即便努力去尝试最小化SAP系统中的自定义内容,通常还是无法避免大量的自定义业务逻辑。在过去,这意味着需要在系统的各种地方引入自定义ABAP代码,包括user-exits,enhancement,BAdi和自定义程序等等。考虑到SAP系统的复杂性和相互依赖性,人们不得不小心翼翼地管理基于ABAP的自定义内容,以保证不同的功能区域的业务逻辑一致、且不重复。
现在,Business Rule Framework Plus(业务规则框架,以下简称BRFplus或BRF+)来了,它是SAP推出的新功能,可以在一个位置、通过可复用的方式管理你的所有自定义业务逻辑。
本文链接:http://www.cnblogs.com/hhelibeb/p/9021665.html
英文标题:BRFplus - a hidden gem within your SAP system
可用性
- 输出表单中的Logo判断
- 服务提醒文档的默认优先级和截止日期判断
- 销售订单的默认工厂判断
- SAP Transportation Management中的默认载具判断
从技术的观点看,BRF+最常见的用例是在user-exits和增强中的自定义业务逻辑实施中。事实上,在这些情况下,BRF+是我们实现自定义业务逻辑的首选实现手段。它在较高层面上可以被描述为2步:
- 在BRF+中创建一个function,依据需要的业务逻辑,它接收输入、进行处理,然后给出输出结果。
- 通过ABAP在user-exits/BAdi/enhancement/自定义程序等地方调用先前创建的BRF+应用。
很重要的一点是,在上述的方式中你还是需要写一些ABAP代码来调用BRF+ function。(和完全使用ABAP代码实现业务逻辑的)区别在于,通常来说,在这种情况下,ABAP代码只负责调用BRF+,不会直接包含业务逻辑。你可能要问这样做的好处在哪里。它的好处是:
- BRF+ function易于复用,通常可以大大地减少系统中重复业务逻辑实现的数量。
- BRF+包含一个巨大的expression库,可以加速映射业务规则的开发过程,特别是这些业务规则比较复杂的情况下。使用ABAP编码来从零开始(from scratch)实现某些东西,也许可以花上数天甚至数周的时间,但是在BRF+里只要使用expression就可以快速地建模实现。
- 你的所有自定义业务逻辑可以在一个地方实现——BRF+事务。你不需要从庞大的自开发程序、增强中搜寻代码以调整现有的业务逻辑。
- 对现有的业务逻辑的简单调整可以经由非编码的方式实现,不需要开发人员的参与。
最后一点值得详细阐述。SAP通常建议通过BRF+工具让业务用户代替ABAP开发者来作为他们自己的逻辑的维护者。坦白说,这种建议有点夸张(exaggerattion)。实际上,BRF+元素(function, expression等)的创建依然是一件相当技术性的活动。大部分没有技术背景的SAP专家可能会发现,想要掌握BRF+的全部内容是件具有挑战性的事情。了解一些基本的编程概念,如变量和循环,会对BRF+的使用起很大帮助,即便你只是通过鼠标来创建这些对象,而不是写ABAP代码。但是撇开陡峭的学习曲线不说,在具备足够多的学习时间和努力的情况下,SAP功能分析师当然是可以精通BRF+的,由此便可以在不依赖开发者的情况下构建复杂的自定义业务逻辑。然而,业务用户完全是另一回事。业务用户对BRF+进行某些实验性的调整是可能的,例如改变已有的decision table中的值,但是BRF+内的主要变更还是需要由IT团队进行。
特性
BRF+中包含很多了不起的特性,使得它是一个杰出的业务规则框架。
expressions
在许多方面上expressions是BRF+中第一个令人心动的东西。它们是预包装的逻辑对象,可以在BRF+环境中大大加速业务规则的建模。虽然BRF+中支持多种表达式类型,但最常用的一种是Decision Table。如果你熟悉SAP系统中的条件技术,decision table会给你相似的感觉,并且它会提供扩展性更强的功能。除了可以从表的顶部检索到底部直到找到匹配的记录为止外,你也可以维护输入值为多值的range、sets、通过空白来表示任意值、以及使用其它一些逻辑操作符等。
customizing and master data applications
定制和主数据应用(customizing and master data applications)是BRF+中的一个灵巧的特性。定制应用需要使用SAP transports来在不同SAP系统之间移动修改,相反主数据应用允许直接在每个SAP系统和client直接进行修改。在你将主数据值,比如客户、供应商、物料等是业务逻辑的一部分时特别有用。记住,因为在多数情况下BRF+通过ABAP调用,function本身需要存在在一个定制应用中。但是这些定制级别的function接下来可以利用存在于主数据级别应用下的expressions(例如decision tables)。一言蔽之,你可以在一个业务规则中混合使用定制和主数据BRF+对象。
user interface
BRF+中的建模大多通过“点击”的用户界面进行,通过事务代码BRF+访问它。你可以通过简单地右击屏幕左侧的节点来创建新的对象,并且通过上下文菜单选择合适的条目。
api
你也可以通过API和BRF+交互。这意味着你不仅可以通过事务BRF+来创建和更新BRF+对象,你也可以通过标准交付ABAP类和方法(standard delivered ABAP classes and methods)实现同样的事情。例如,在某个场景中我们需要存储美国的柴油平均价到BRF+的decision table中。我们可以创建一个自定义ABAP程序通过公网服务来查找上周的柴油价格,并且最后经由BRF+ API更新decision table。
web services
BRF+ functions可以很容易地暴露为web services。这意味着你可以同时在SAP和非SAP系统中消费BRF+业务逻辑。
helper tools
BRF+伴随着大量的工具,可以帮助你开发、导入/导出、检查和BRF+对象和排查故障。其中某些工具可以从BRF+事务中的菜单访问,不过最简单的查找他们的方式是在SE38中运行程序FDT_HELPERS。较早地了解这些工具,你就可以在将来省下很多时间。例如,下图里选中的工具允许你快速地识别和解决大部分有关系统间传输BRF+对象的问题。
总而言之,大部分SAP客户都可以在不需要额外许可证的条件下使用BRF+。我们鼓励你仔细了解BRF+、并且开始为你的自定义业务逻辑需求使用它。
我的BRF+教程系列:http://www.cnblogs.com/hhelibeb/tag/BRFplus/
ABAP on HANA之CDS Association和Path Expression
本文阐述了ABAP CDS association的概念,并且展示了在CDS视图中和SQL语句中写路径表达式(Path Expression)代码的方法。我也会解释如何在CDS asociation中指定inner join——默认情况下是left outer join,以及如何为association添加过滤。
对于CDS的相关开发,SAP希望我们使用association而不是join,因为association更加接近“概念思维”。基本上,association本身不是join,它只是有关join连接可能性的元数据,它会按需成为join。真实的join会在路径表达式使用association的时候被创建。
一个简单的CDS association例子,它看起来和left outer join没区别:
@AbapCatalog.sqlViewName: 'ZCDS_ASSOC11'defineview zcds_assoc1 as select from scarr assca
association[0..1] to spfli as_spflion sca.carrid =_spfli.carrid
{* }
SAP S/4嵌入式分析——虚拟数据模型(VDM)
在本文中,我会通过CDS视图来介绍虚拟数据模型(Virtual Data Model,以下简称VDM)。
在SAP HANA平台出现后,SAP的业务应用开发模式已经产生了变化,新的经验法则是:尽可能在数据库中做更多的事情(PUSH DOWN),以得到最佳的性能。
本文链接:https://www.cnblogs.com/hhelibeb/p/9223993.html
嵌入式分析
SAP S/4嵌入式分析是S/4的一部分,用于对业务数据执行复杂的实时报表和分析。SAP S/4嵌入式分析的关键架构组件包括SAP HANA数据库,VDM,分析引擎(嵌入式SAP BW),OData服务,和如下图所示的接口。
本文将介绍其中的VDM。
CDS视图
为了在应用开发中利用SAP HANA的优点,SAP引入了新的数据建模基础设施,名为Core Data Service(以下简称CDS)。通过CDS,数据模型会在数据库而非应用服务器中定义和消费。CDS也提供了传统数据建模工具的兼容性,包含支持概念建模和关系定义,内置函数和扩展。
技术上讲,CDS是提供数据定义语言(DDL)的加强版SQL,用于在数据库中定义富语义数据库表/视图(CDS entity)和用户定义的类型。增强包括:
- Expression:用于在数据模型中计算和查询。
- Association:在概念层上,通过简单的path expression代替join(关于Association可参考之前的文章)。
- Annotation:通过附加的(特定领域的)元数据来丰富数据模型。
CDS在ABAP和SAP HANA中都得到了原生支持。数据模型通过数据定义语言(DDL)表达,并且定义为CDS视图,可以在ABAP程序中通过Open SQL语句访问。CDS为业务和开发提供了一系列优点,包含:
- 富语义数据模型:CDS基于众所周知的实体-关系模型,并且实质上是声明式的,非常接近概念思维。
- 兼容任何数据库平台:CDS会被生成为受管理的Open SQL视图,并且原生地集成进入SAP HANA层。这些基于Open SQL的视图得到了所有主流数据库供应商的支持。
- 高效:CDS提供了多样化和高效的内置函数,例如SQL运算符,聚合和表达式,来帮助开发者构建视图。
- 支持annotation:CDS语法支持特定领域的annotation,可以轻松的被其他组件利用,比如UI,分析和OData服务。
- 支持概念关联(conceptual associations):CDS帮助你定义association,作为不同视图的关系。Path expression可以用于在关系间导航。association引入了抽象的外键关系和join,来对可消费的entity进行导航。
- 可扩展性:客户可以扩展SAP定义的CDS视图,扩展字段将随其使用层次结构自动添加到CDS视图中。
VDM
在HANA之前,查询ERP系统中的大量数据集会花很多时间,并会降低系统的整体性能。数据仓库可以通过高级建模技术创建持久化的数据模型,以提高查询性能。SAP HANA去除了ERP中的性能问题,使我们能够直接在ERP中创建虚拟数据模型(VDM),并提供令人难以置信的高性能。
VDM是什么?VDM是富语义CDS视图的结合,它将ERP源表的数据符合逻辑地结合到一起,创建成为有意义的数据集,并且可以被前端工具便利地消费。
VDM的核心原理是在现有的S/4数据库模型之上构建语义层,隐藏它的技术细节。基于提供的内容和复用选项,VDM中的CDS视图被分为接口视图或消费视图,如下:
私有视图
私有视图(Private Views)实际上不是提供给终端用户消费的视图,它是技术驱动的辅助视图。引入私有模型是为了帮助底层数据模型到公共视图模型的转换。私有CDS视图的名字前缀是P_。不建议修改或扩展它们。
接口视图
接口视图(Interface views)是VDM最重要的组成部分。接口视图组成了可复用的entity视图,在业务语义是定义上的重点。接口视图对任何消费者而言都是公开的、稳定的并且可复用的。公共接口视图的结构需要不受correction、补丁和升级的影响。
接口视图分两种:
基本接口视图(Basic interface Views)代表没有数据冗余的核心entity,即对每个核心entity做单一的表示,(比如,正好一个客户或者销售订单)并且只带有依赖于核心entity自身的、无法从其他字段计算得到的字段。基本视图组成了低冗余模型和SAP Business Suite数据库表的简单投影。
组合接口视图(Composite Interface Views)继承自多个简单接口视图,也许会有关联、聚合和复杂计算。它们可以属于特定消费域,或者被复用,根据设计,它们总是暴露冗余的数据。按照实际的使用情况,组合接口视图可以分为很多层。
消费视图
如名字所示,消费视图(Consumption Views)是暴露给终端用户消费的视图。消费视图会使用到一个或更多接口视图。消费视图是共用的特定领域视图,用于分析、搜索和事务应用。VDM建模的指导原则是,数据库表一定不可以被消费视图直接访问(即不可以绕过接口视图)。
扩展包含视图
扩展包含视图(Extension include Views)用于暴露自定义新字段。可以扩展SAP发布的扩展包含视图,以条件附加字段。自定义扩展包含视图会在单独的DDL源中创建和传输。
总之,在高层上,CDS视图从数据库表得到数据,这些视图又会被其它CDS视图读取,VDM就是由所有的这些CDS视图组成。没有任何持久化过程,一切都是实时的。
Annotation
Annotation用于描述CDS视图,为CDS视图中的字段提供语义和意义。
- 它可以应用在整个CDS视图entity上;
- 它可以指定SELECT列表中特定的字段的语义;
- 总是在@符号后面
这面是annotation的列表:https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abencds_annotations_sap.htm
也可以通过以下路径访问:ABAP – Keyword Documentation > ABAP – Dictionary > ABAP CDS in ABAP Dictionary > ABAP CDS – Syntax > ABAP CDS – Annotations
下面是用于VDM的定义整个CDS视图的一些关键的annotation:
Annotation | Description |
VDM.viewType | 定义VDM视图的类型 |
Analytics.dataCategory | 分析查询可以在CDS视图之上定义。通过指定数据分类,开发者可以提供指令和hints,告诉analytic manager如何解释各个实体。 |
Analytics.dataExtraction.enabled | 应用开发者通过该annotation标记适合于数据复制的视图(例如,必须为海量数据提供增量复制能力)。 |
Analytics.query | 通过标记CDS视图,开发者可以指定暴露给analytic manager的视图。这类视图会被analytic manager解释为分析查询。 |
ObjectModel.dataCategory | 定义数据分类(#TEXT 或 #HIERARCHY) |
ObjectModel.representativekey | Most specific element (field or managed association) of the primary key (indicated by the keyword KEY) that represents the entity which the view is based on |
AccessControl.authorizationCheck | 针对指定的CDS视图启用行级别权限控制 |
/名词解释:analytic manager是一个BW概念,它提供OLAP功能和服务,以及BW集成规划和分析过程设计的服务。
因为我还是个BW开发者,我找了几个最重要的VDM的annotation来和BW对象对比:
Annotation: @VDM.viewType
Value | Description | BW对等物 |
#BASIC | 组成核心基础的视图,无数据荣誉,它只是从数据库物理表的SELECT。 | 等于ADSO(高级数据存储对象),即通过某些ETL后的raw data。 |
#COMPOSITE | 提供从基础视图继承和/或组合而成的数据 | 等同于Composite Provider,是允许进行join和union的虚拟数据层。 |
#CONSUMPTION | 为特定应用目的服务的视图,也许会基于公共接口视图定义(比如BASIC 视图或COMPOSITE视图) | 等于BW Query,可以指定特殊的样式,变量,RKF,CKF,总计,等等。 |
Annotation: @Analytics.dataCategory
Value | Description | BW对等物 |
#DIMENSION | 表示主数据的视图需要有annotation:ObjectModel.dataCategory: #DIMENSION | 等于Infoobject Attributes |
#FACT | 事实表表示业务数据(星型模型的中心)通常包含度量。这些视图通常是复制所必须的,因此,他们不能和主数据视图join。 | 等于从一个单一数据源加载的ADSO,没有任何主数据。 |
#CUBE | CUBE也代表事实数据,和FACT很像,但是CUBE不必是无冗余的。这意味着它可以和主数据join。查询基本都是构建在CUBE之上的,CUBE从FACT复制数据。 | 等于从单一/多个数据源加载的ADSO,和主数据的attributes/texts/hiererachies连接。 |
我的BRF+自学教程(二):跟踪模式(trace mode)
使用自开发程序来处理业务逻辑时,处理过程通常是个黑箱,业务顾问和业务用户不知道程序的具体运行方式,要依赖文档和频繁的沟通来确认实际情况。
BRFplus可以通过配置的方式实现业务逻辑,使得业务人员把业务逻辑的实现掌握在自己手中,此外,跟踪(tracing)功能的存在使得业务逻辑应用的执行情况也变得清晰可见。
本文链接:https://www.cnblogs.com/hhelibeb/p/9556478.html
目的
跟踪模式有以下用处:
- 有助于找到BRF+应用运行结果与预期不一致的原因。
- 统计各规则的使用情况,从而理解规则调整的影响和风险。
- 统计输出结果的分布情况。
跟踪信息可以帮助人们进一步理解业务的实际执行情况,确定哪些场景是常见的、哪些是偶然的甚至永不出现的,从而进一步优化业务逻辑实现。
实现
虽然跟踪模式可以服务业务,但是因为BRF+应用需要通过ABAP代码来调用,所以实现部分会是和ABAP相关的内容。
我创建了一个简单的BRF+应用,其功能是根据输入的采购订单编号,到数据库表EKKO中查询采购组和采购订单类型,根据这两个字段的组合,来决定是否需要审批。涉及到2个表达式,1个是数据库查找(DB lookup),还有一个是决策表(decision table)
调用
ABAP调用代码,
REPORTztest_brf3.PARAMETERS: p_ebeln TYPEebeln.START-OF-SELECTION.*获取function实例 DATA(lo_fuction) =CAST cl_fdt_function(
cl_fdt_factory=>if_fdt_factory~get_instance(
)->get_function( '005056A4CCA61ED8AAF183894A92CC2B') ).*获取context实例 DATA(lo_context) =CAST cl_fdt_context(
lo_fuction->if_fdt_function~get_process_context( ) ).*将将采购订单号输入到context lo_context->if_fdt_context~set_value(
: iv_name= 'EBELN' ia_value =p_ebeln ) .*处理,获取结果和跟踪数据 lo_fuction->if_fdt_function~process(EXPORTING io_context =lo_context
iv_trace_mode= if_fdt_constants=>gc_trace_mode_leanIMPORTING eo_result = DATA(lo_result)
eo_trace= DATA(lo_trace) ).
我的BRF+自学教程(三):动态技术
开发者们可以在编程中使用各种动态技术,比如RTTS,比如通过动态的类创建和多态来实现功能的平滑扩展。BRF+开发中也存在一些动态手段。本文将介绍3种不同场景下的动态实践方式。其中第一种是纯配置的,第二和第三种是编程相关的。
本文链接:https://www.cnblogs.com/hhelibeb/p/9571707.html
我的BRF+教程系列:https://www.cnblogs.com/hhelibeb/tag/BRFplus/
1,动态表达式(Dynamic Expression)
动态表达式是一种特殊类型的表达式,它可以用来实现对其它表达式的动态调用。动态表达式的应用场景之一是,有很多个表达式可以供用户选择,这些表达式使用基本一样的上下文对象,你不希望为每个表达式创建一个函数(因为创建它们的过程太繁琐),而是希望在一个统一的入口函数去调用。
1)选项
- 被调用的表达式(Called Expression):选择一个表达式,将它分配给动态表达式。被分配的表达式会在运行期间被动态表达式调用。注意,虽然被称为被调用的表达式,但是它并不是被动态调用的表达式,它的返回结果才是被动态调用的表达式的ID。Called Expression可以处理动态表达式的上下文,结果中必须包含一个表达式的ID,该表达式的结果会被传回给动态表达式。
- 结果数据对象(Result Data Object:)结果数据对象可以使用任何种类的对象。然而,很重要的一点是确保第二个被调用的表达式的结果数据对象和动态表达式的结果数据对象是兼容的。
2)限制
动态表达式可以提供灵活性,但它也有缺陷,因为动态表达式类型的特质,使得某些大部分可以应用在其它BRF+表达式上的检查无法应用在动态表达式上面。所以这可能导致一些设计缺陷无法被检查出来,只有在运行期间才会暴露。此外,动态表达式是不支持代码生成模式的,只能使用解释模式,这使得它的性能不太好,在对时间要求高或数据负载量大的时候不建议使用它。
3)例子
实际操作部分比较简单,读完上面的文字之后应该可以很顺利地出来,这里就不再一图一图地贴了。可以参考官方文档。
2,动态创建决策表(Decision Table)
通过使用ABAP代码,可以动态地创建BRFplus中的decisiong table和function等对象。
(本节的内容基本来自于Create decision table & it’s entries dynamically in BRF + Workbench through API)
1)前提
要读懂本节,需要两方面的知识,
- 基本的ABAP面向对象知识。
- 基本的BRF+知识。
2)需求
通过一个简单的report程序来创建决策表和它的条目。
3)使用的接口
- IF_FDT_FACTORY
- IF_FDT_DECISION_TABLE
- IF_FDT_FUNCTION
4)创建应用
在工作台中创建一个应用,接下来将会在这个应用中动态地创建决策表。
5)复制代码
把以下代码粘贴到自定义程序中,代码的具体意义写在注释中,注意ID要替换成你自己创建的BRF+应用的ID
DATA: lo_factory TYPE REF TOif_fdt_factory,
lt_messageTYPE if_fdt_types=>t_message,
lv_messageTYPE string,
lv_booleanTYPEabap_bool,
lo_elementTYPE REF TOif_fdt_element,
lo_tableTYPE REF TOif_fdt_table,
lo_structureTYPE REF TOif_fdt_structure,
lv_element1_idTYPE if_fdt_types=>id,
lv_element2_idTYPE if_fdt_types=>id,
lv_element3_idTYPE if_fdt_types=>id,
lv_structure_idTYPE if_fdt_types=>id,
lo_constantTYPE REF TOif_fdt_constant,
ls_elementTYPE if_fdt_structure=>s_element,
lts_elementTYPE if_fdt_structure=>ts_element,
lv_stringTYPE string,
ls_rangeTYPE if_fdt_decision_table=>s_range,
ls_table_dataTYPE if_fdt_decision_table=>s_table_data,
lo_decision_tableTYPE REF TOif_fdt_decision_table,
lo_functionTYPE REF TOif_fdt_function,
lo_contextTYPE REF TOif_fdt_context,
lts_context_idTYPE if_fdt_types=>ts_object_id,
lts_table_dataTYPE if_fdt_decision_table=>ts_table_data,
lts_columnTYPE if_fdt_decision_table=>ts_column,
lv_actv_failedTYPEabap_bool,
lx_fdtTYPE REF TOcx_fdt,
lv_dt_idTYPE if_fdt_types=>id,
ls_columnLIKE LINE OFlts_column.FIELD-SYMBOLS: <ls_message> TYPE if_fdt_types=>s_message,<lv_value> TYPEany.*获取FDT工厂实例,使用上面创建的应用IDlo_factory= cl_fdt_factory=>if_fdt_factory~get_instance('005056A4CCA61ED8AA9AAF84A7712616' ).
*创建数据对象lo_element ?= lo_factory->get_data_object(
iv_data_object_type= if_fdt_constants=>gc_data_object_type_element ).
lo_element->if_fdt_transaction~enqueue( ).
lo_element->if_fdt_admin_data~set_name( 'IV_VAR1').
lo_element->set_element_type( if_fdt_constants=>gc_element_type_text ).
lo_element->if_fdt_transaction~activate(IMPORTINGet_message=lt_message
ev_activation_failed=lv_boolean ).IF lv_boolean EQabap_true.*如果激活失败,需要处理 lo_element->if_fdt_transaction~dequeue( ).ELSE.
lo_element->if_fdt_transaction~save( ).
lo_element->if_fdt_transaction~dequeue( ).*通常需要把ID单独存下来,以便后续操作lv_element1_id= lo_element->mv_id.
ls_element-position = 1.
ls_element-element_id =lv_element1_id.APPEND ls_element TOlts_element.ENDIF.INSERT lv_element1_id INTO TABLElts_context_id.*创建另一个元素 lo_element ?= lo_factory->get_data_object(
iv_data_object_type= if_fdt_constants=>gc_data_object_type_element ).
lo_element->if_fdt_transaction~enqueue( ).
lo_element->if_fdt_admin_data~set_name( 'IV_VAR2').*设置元素类型(可以搜索if_fdt_constants=>gc_element_type_* 得到可用元素类型列表 lo_element->set_element_type( if_fdt_constants=>gc_element_type_text ).
lo_element->if_fdt_transaction~activate(IMPORTINGet_message=lt_message
ev_activation_failed=lv_boolean ).IF lv_boolean EQabap_true. lo_element->if_fdt_transaction~dequeue( ).ELSE.
lo_element->if_fdt_transaction~save( ).
lo_element->if_fdt_transaction~dequeue( ). lv_element2_id= lo_element->mv_id.
ls_element-position = 2.
ls_element-element_id =lv_element2_id.APPEND ls_element TOlts_element.ENDIF.INSERT lv_element2_id INTO TABLElts_context_id.*创建结果数据元素 lo_element ?= lo_factory->get_data_object(
iv_data_object_type= if_fdt_constants=>gc_data_object_type_element ).
lo_element->if_fdt_transaction~enqueue( ).
lo_element->if_fdt_admin_data~set_name( 'EV_RESULT').
lo_element->set_element_type( if_fdt_constants=>gc_element_type_text ).
lo_element->if_fdt_transaction~activate(IMPORTINGet_message=lt_message
ev_activation_failed=lv_boolean ).IF lv_boolean EQabap_true. lo_element->if_fdt_transaction~dequeue( ).ELSE.
lo_element->if_fdt_transaction~save( ).
lo_element->if_fdt_transaction~dequeue( ). lv_element3_id= lo_element->mv_id.
ls_element-position = 3.
ls_element-element_id =lv_element3_id.APPEND ls_element TOlts_element.ENDIF.INSERT lv_element3_id INTO TABLElts_context_id.*填充第1列元素ls_column-col_no = 1.
ls_column-object_id =lv_element1_id.
ls_column-is_result =abap_false.INSERT ls_column INTO TABLElts_column.* 填充第2列元素
ls_column-col_no = 2.
ls_column-object_id =lv_element2_id.
ls_column-is_result =abap_false.
INSERT ls_column INTO TABLElts_column.
*填充结果列元素
ls_column-col_no = 3.
ls_column-object_id =lv_element3_id.
ls_column-is_result =abap_true.
INSERT ls_column INTO TABLElts_column.
*创建并设置决策表表达式
lo_decision_table ?= lo_factory->get_expression( iv_expression_type_id= if_fdt_constants=>gc_exty_decision_table ).
*对表达式加锁.
lo_decision_table->if_fdt_transaction~enqueue( abap_true ).
*设置表列
lo_decision_table->set_columns( its_column =lts_column ).
lo_decision_table->if_fdt_admin_data~set_name( 'DT_TEST' ). "user defined name. DT_TEST is the decision table Name
*使用工厂对象创建一个函数实例.
lo_function ?= lo_factory->get_function( ).
*对函数加锁.
lo_function->if_fdt_transaction~enqueue( ).
*设置函数上下文对象.
lo_function->set_context_data_objects( lts_context_id ).
lo_function->if_fdt_admin_data~set_name( 'FN_TEST' ). "自定义函数名
*设置函数根表达式.
lo_function->set_expression( lo_decision_table->mv_id ).
*设置单元格(1,1)的条件
ls_table_data-row_no = 1.
ls_table_data-col_no = 1.
ls_range-position = 1.
ls_range-sign = if_fdt_range=>gc_sign_include.
ls_range-option = if_fdt_range=>gc_option_equal.
CREATE DATA ls_range-r_low_value TYPE if_fdt_types=>element_text.
ASSIGN ls_range-r_low_value->* TO <lv_value>.<lv_value> = 'MOURI'.
INSERT ls_range INTO TABLE ls_table_data-ts_range.
INSERT ls_table_data INTO TABLElts_table_data.
CLEARls_table_data. .
*设置单元格(1,2)的条件
ls_table_data-row_no = 1.
ls_table_data-col_no = 2.
ls_range-position = 1.
ls_range-sign = if_fdt_range=>gc_sign_include.
ls_range-option = if_fdt_range=>gc_option_equal.
CREATE DATA ls_range-r_low_value TYPE if_fdt_types=>element_text.
ASSIGN ls_range-r_low_value->* TO <lv_value>.<lv_value> = 'TECH'.
INSERT ls_range INTO TABLE ls_table_data-ts_range.
INSERT ls_table_data INTO TABLElts_table_data.
CLEARls_table_data.**在单元格(1, 3)得到结果
ls_table_data-row_no = 1. ls_table_data-col_no = 3.
CREATE DATA ls_table_data-r_value TYPE if_fdt_types=>element_text.
ASSIGN ls_table_data-r_value->* TO <lv_value>.<lv_value> = 'MOURITECH'.
INSERT ls_table_data INTO TABLElts_table_data.
CLEARls_table_data.
*设置完全的表数据.
lo_decision_table->set_table_data( its_data =lts_table_data ).
*保存并激活.
lo_function->if_fdt_transaction~activate(
EXPORTING iv_deep =abap_true
IMPORTING et_message =lt_message
ev_activation_failed=lv_actv_failed ).
*如果成功,先保存对象。无论成功失败,释放全部锁
IF lv_actv_failed EQabap_true.
lo_function->if_fdt_transaction~dequeue( iv_deep =abap_true ).
WRITE : / 'Deep activation failed'.
LOOP AT lt_message ASSIGNING <ls_message>.
MESSAGE ID <ls_message>-msgid TYPE <ls_message>-msgty NUMBER <ls_message>-msgno
WITH <ls_message>-msgv1 <ls_message>-msgv2 <ls_message>-msgv3 <ls_message>-msgv4INTOlv_message.
WRITE: / 'Reason : -',lv_message.
ENDLOOP.
ELSE.
TRY.
lv_dt_id= lo_decision_table->mv_id.
lo_function->if_fdt_transaction~save( iv_deep =abap_true ).
WRITE : 'The ID of the decision table created is:',lv_dt_id. .
CATCH cx_fdt INTOlx_fdt.
WRITE : / 'Save failed with exception'.
LOOP AT lx_fdt->mt_message ASSIGNING <ls_message>.
WRITE :/ <ls_message>-text.
ENDLOOP.
ENDTRY.
lo_function->if_fdt_transaction~dequeue( iv_deep =abap_true ).
ENDIF.