文章目录
MDG数据处理
简介MDG数据处理逻辑
首先需要从技术角度简单的了解一下SAP MDG数据处理的大体逻辑(正如我一贯认为,MDG是一个技术系统而不是业务系统,所以顾问需要有一定的技术背景,这些技术储备需要比一般的业务顾问多得多)。
在MDG数据处理的过程中,Entity Data来自不同的数据源,包括Active Data和Staging Data(Inactive Data)。活动数据Active Data是指在系统中真正有效的数据,也就是说这些Active Data可以随时被外部的应用和业务过程调用。同时,MDG系统本身也有大量的数据,依赖于Change Request(变更请求)而存在,这些数据独立的存储于Active Data之外。我们于是称之为非活动数据Inactive Data或临时数据Staging Data。当这些变更请求被最终审批通过后(Final Approved),与各个变更请求相关的非活动数据被转换为相应的活动数据。这个过程在MDG系统中叫做变更请求的**Change Request Activation。
我们都知道,MDG Entity Type可以被分为两种,Flex Entity Type和Reuse Entity Type。Flex Entity Data没有独立的活动数据存储区,而是将Active和Inactive Data同时存储于MDG 临时表Staging Table中。对于Flex Entity Data的所有读写操作,都是通过MDG抽象层和随后的MDF层进行的。
Reuse Entity Type拥有他们自己的活动数据存储区域。数据的读写一般会从抽象层委托到各自的访问类Access Class。非活动数据则与Flex Entity Type一样,存储在MDG临时表中。除了非活动数据外,Reuse Entity Type还拥有快照数据Snapshot Data。这些快照数据是从活动数据复制而来的,于Reuse Entity被插入进变更请求对象列表Change Request Object List的时候创建。就像非活动数据一样,这些快照数据同样存储于临时表中。对于这些快照和非活动数据的访问总是从抽象层开始,使用MDF来实现。
读取Entity Data
读取Entity Data的过程如下图所示:
Entity Data 可以使用Convenience API, Governance API和External Model API进行读取。无论使用哪种API,读取的请求都会首先委派给MDG抽象层。抽象层负责将请求发送给MDF或访问类,然后将结果进行合并,反馈给调用者。
在一个SAP LUW中还未进行保存的数据,会被放置到MDF的缓存区中。默认情况下,数据读取请求会使用MDF缓存区中的数据作为组成结果的一部分(另一部分为访问类)。
SAP LUW 逻辑工作单元 是SAP技术概念中最为基础和重要的内容之一,提供了多个对话操作过程中保持数据一致性的解决方案。详细内容请参见https://help.sap.com/saphelp_scm50/helpdata/en/41/7af4bfa79e11d1950f0000e82de14a/content.htm?no_cache=true
通常来说,读取的结果取决于请求参数和不同存储位置及MDF缓存区中的数据组合。API中的使用的参数决定了哪些数据将要被读取(例如,读取活动还是非活动数据,需要考虑变更请求内的非活动数据分配情况,Select条件,过滤条件和Edition等)。
修改Entity Data
Entity数据可以由数据写入或派生进行修改。在这两种情况下,修改过程中的数据分别存储于不同的位置,直到它们成为活动数据为止。这个流程参见以下架构图:
Entity Data 可以使用Change Request API, Convenience API 和 Governance API进行读取。无论使用哪种API,修改的请求都会首先委派给MDG抽象层。抽象层包含了它自己的临时增量缓存Delta Buffer。知道这一点非常关键,因为这意味着任何对抽象层缓存的修改,都不会被任何读取请求发现。为了让这些修改的内容可以被读取到,需要首先将抽象层的增量缓存转移到MDF缓存中,这一过程称之为Flush。在这样一个Flush期间,一些派生Derivation的调用可能会进一步的变更数据。
为了处理不同缓存区和不同数据的修改场景,抽象层提供了不同的写入模式:
- Direct Mode: 在这种模式下,变更的数据被直接写入MDF缓存。不会涉及增量缓存和Flush。
- Direct Mode with Derivation:在这种模式下,变更的数据首先被写入增量缓存(包含了预先Collect的变更),然后这个缓存区的所有内容会被转移到MDF缓存(Flushed)。
- Collect Mode:在这种写入模式下,变更数据首先会被收集Collect到增量缓存中。不涉及MDF缓存和Flush。
一次Flush可以被应用在任意时间点通过调用对应的Flush方法来实现。此外,当任何读取或写入操作发生时,系统会自动触发一次Flush。
当保存或提交变更请求时,变更的数据作为非活动数据,从MDF缓存写入MDF临时表中。在后续变更请求审批通过并且**时,这些非活动数据会被转换成活动数据。此流程终结于MDGStage Tables(Flex Entity Types)或Reuse Tables(Reuse Entity Types)。
派生 Derivations
派生(数据推导)可以被用于自动修改数据,而不需要人为交互。MDG提供了多种派生可能,何时、何地、何种派生方式。以下列出最重要的几种派生方式:
- Standard Derivations: 标准的派生可以使用BADI USMD_RULE_SERVICE下的方法IF_EX_USMD_RULE_SERVICE~DERIVE_ENTITY或BRF+实现。标准派生一般在使用Gov API或CR API写入数据时自动触发,或者一些特殊情况下由应用手工触发。
- Derivations in Access Classes: 访问类接口IF_USMD_PP_ACCESS提供了DERIVE_DATA方法用于实施该种派生。此方法在Flush期间以每个访问类为单元进行调用,并获取增量缓冲区的当前内容,以查明自上次Flush以来收集了哪些数据变更。
- Cross entity derivations: 这些派生可以使用BADI USMD_RULE_SERVICE下的方法IF_EX_USMD_RULE_SERVICE2~DERIVE来实现。和上面一种派生类似,此方法同样于Flush中调用,通过获取当前增量缓冲区的数据内容来查明上次Flush依赖Collect了哪些数据变更。Cross 派生位于Access派生后进行调用,可以获取到Access派生中修改的内容。
如果一些额外的Entity Data需要在派生中获取,记住只能使用External Model Interface(永远不要使用Gov或Conv API)。为了避免没有必要的Flush和派生(以免造成死循环),NO_FLUSH参数需要设置为‘X’。
下图总结了几种派生方式的顺序关系:
以上大部分内容翻译自MDG API官方手册:
Master Data Governance Application Programming Interface Guide
实战:运用技术知识解决实际问题
用户问题
用户在使用系统的过程中,发现对于当前状态 = Final Checked Approved的变更请求,也就是已经审批通过并成功**的变更请求进行查看时,界面丢失ERP Vendors的信息。但如果是通过MDG搜索界面直接搜索该BP,并显示Active Data则不会出现该问题。
问题分析
需要注意到这个问题的关键在于:使用Change Request 显示已经**的数据,丢失部分信息。使用Object Key直接查询Active Data则没有问题。首先思考,这两种情况的区别在哪里?
-
Change Request Display搜索的条件是CR Number + Object Key。而Search Active
Data仅使用Object Key作为搜索条件。因为BP是Reuse Mode,所以对于这种已**的数据,Staging
Table中不会存在记录。 -
需要注意的是,只有状态 = Final Approved的数据才会出现这个问题,审批过程中一切正常。说明当非活动数据是可以正常获取的。
那么现在主要把关注重点放在非活动数据转换成活动数据的时候会不会出现了什么问题。参照上面所讲述的MDG数据处理逻辑,问题可能发生在MDF或抽象层,由于用户系统存在大量客制化代码,下面通过Debug来追溯问题根源,Debug之前我们需要了解MDG应用的大体架构如下图,既然问题发生在前台,因此需要遵循此架构从展示层开始一步一步查找问题:
展示层
检查UIBB Feeder Class的GET_DATA方法,发现无论是CT_DATA还是MO_COLLECTION中都没有ERP Vendor的相关数据。MO_COLLECTION来自于FPM组件初始化过程,数据内容来自FPM Connector,也就是我们在FPM Configuration中配置的Wire。
Connector是Genil和FPM BOL的桥梁,可以很简单的获取到Connector Class在如下的配置点:
BOL层
将断点置于Connector Class CL_BS_BP_CONNECTOR_BOL_REL的PROCESS_RELATION方法中,该方法可以从父节点通过关系获取到子节点的数据内容。
下面的截图对比了使用CR读取数据和Object Key直接读取活动数据的区别。
我们可以从左边发现CR读取时并没有获取到SP_MULTIPLEASSIGNMENT的关系,这意味着数据丢失发生在更底层。
Genil层
MDG BP模型使用了多个Genil Class应用于不同的Genil Model。在这个例子中,由于ERP Vendor是属于BP Multiple Assignment的,所以让我们将断点设在MLT_ASSIGNMENT的Genil Class中。
通过Debug发现,此时Entity BP_MLT_AS依旧无法获取到数据。
继续在Genil Class中向内部调试,找到了调用API的地方。
MDG API层
让我们来看一下使用CR和只使用Object Key在调用MDG API时存在什么区别。
Display Change Request:参数MV_CREQUEST_ID不为空
Display Business Partner:参数MV_CREQUEST_ID为空
此外他们都使用BP_HEADER = 0005061112作为Object Key。
除了一个参数不同外,还有哪些关键的区别呢?
读取模式。Display CR中的读取模式 = 1(默认),因为在变更请求的不同阶段(状态),读取模式会动态变化。比如处于审批过程中的数据,属于非活动数据,因此需要从临时表中获取数据。但是当变更请求**后,状态变为Final Approved,此时非活动数据不复存在,当我们尝试Display CR时,会从活动区域来获取数据。所以通过CR的读取模式 = 1,是动态的。
对于Display BP来说,因为本身查看的就是活动数据,所以只用Object Key来读取数据的模式固定 = 3(无非活动数据),这很好理解,会直接从**区域获取数据。
可是,Debug中却显示,现在即使我们在读取一个Final Approved的CR,逻辑还是指向读取Staging数据,这就是问题所在。**的ERP Vendor数据肯定无法再去使用Read Staging来获取到。
解决方案和结论
用户的定制化代码导致标准的MDF缓存错乱,引导系统使用了错误的读取模式。对Multiple Assignment这个Entity来说,尝试对于已**的数据仍使用Read Staging方法进行读取。必然导致获取不到ERP Vendor的数据。当注释掉用户对应的代码后,问题得到了解决。