业对象和BAPI
Term/Synonym | Definition |
Business object (BO) | 1. 业务对象,封装了与该对象相关的数据与方法; 2. 每个业务对象都必须定义关键字段,用于唯一确定一个特定的业务对象; 3. 业务对象中某些通用的方法具有标准的定义格式(如getlist); 4. 业务对象中定义的方法分为Instance-dependent方法与instance-independent两类。 |
Business Object Repository | 业务对象仓库。 |
Business Application Programming Interface(BAPI) | 1 访问R3中业务对象与业务过程的标准编程接口。 2 BAPIs 定义了BOR中业务对象的方法。 3 BAPIs 通过RFC-enable的功能模块实现。 4 用户可以自行开发新的BAPI以满足业务需求。 |
SAP业务对象(SWO1)
业务对象是现实世界中对象在SAP系统中的抽象,其内部封装了业务逻辑,并可以通过BAPI方法从外部进行访问,为SAP系统中的数据和流程提供了面向对象的视图。SAP中业务对象最初是为工作流系统的实现而开发的,但到目前,已广泛应用于整个SAP系统中的各个领域,如ArchiveLink、数据传输、GOS(Generic Object Service)系统等
业务对象通过组件存储信息,包括接口、关键字段、属性、方法和事件等,其中,关键字段和属性对应底层数据库表中的字段,具体的业务对象实例存储在相关的数据库表中。方法分为同步和异步两种,可以通过ABAP代码、事务、函数和报表来实现,通过BAPI函数实现的方法称为BAPI方法。上述组件通过一个ABAP程序与业务对象类型进行集成,在技术上实现SAP业务对象的构架:
业务对象类型是业务对象的定义和描述,面向对象架构的实现基础,也就是SAP系统中的“类”,它封装了业务功能和数据,一个业务对象即为一个业务实体,其中不仅包含业务对象本身的数据,还包含其功能的实现,根据业务规则来组织数据和业务过程。例如一个物料业务对象,其数据传输方法和具体业务应用的实现都整合在该对象中
业务对象整体架构包含四层:
l 最内层SAP业务对象内核层,包含对象本身的内部数据结构及标准设定,如一个职员的姓名年龄、地址等
l 整合层,包含对象的业务逻辑。如一个职员的性别属性只能输入特定值、一个销售组织只能将货物销售给已经定义的业务伙伴等
l 接口层,提供该业务对象类型的外部访问接口,包括属性、方法、BAPI方法、事件等,这些方法代表着业务对象的行为,它们可以访问对象的数据,并改变一个对象的当前“状态”
l 外部访问层,定义了支持对业务对象数据访问的具体技术,如RFC\JCo\NCo等位于该层,这些技术通过接口层中定义的接口操作数据对象
业务对象仓库浏览器的事务代码是SWO3:
业务对象在业务对象浏览器中定义,业务对象创建器SWO1:
在SWO1中可以根据业务对象类型来查看它所对应的业务对象,知道业务对象后就可以在BAPI浏览器查找了:
面向对象中的“类”和“对象”的区别在于,一个是抽象化的概念,一个是具体的实例。SAP系统也是如此,系统中每个单独的业务对象即为这类业务对象的实例,包含具体的数据。如物料A01、B02均为“物料”类的实例。业务对象类型也是可以继承的,如业务对象类型BUS1001006(标准物料)和BUS1001001(零售物料)的父类型都是BUS1001(物料):
SAP业务对象不支持多重继承,即一个业务对象类型只能制定唯一的父类型,但一个对象可以实现多个接口,如下图中的物料业务对象类型BUS1001就实现了多个SAP接口,这些接口中定义的方法将在该对象类型中重新实现:
接口中仅定义属性和方法的名称,但不能包含具体实现
业务对象类型的组成
业务对象类型组件:SAP对象的接口、属性、方法、事件
l 接口:本身就是一种特殊的业务对象类型,不能生成对象实例,但可以作为其它业务对象类型的接口组件, 其属性和方法或事件会自动添加到实现它的业务对象类型中
l 关键字段:用于唯一确定一个业务对象类型的实例,通常是业务对象底层数据库表的对应主键
l 属性:业务对象的数据部分, 可以是数据表中的字段、运行值(又称虚拟属性, virtual attribute) 或指向其它业务对象的指针(对象引用, object reference)等。其中,对象引用多用于工作流设计过程
l 方法:用于操作业务对象属性,可以通过调用事务、function module、 report 或ABAP 代码来完成。方法是外界对业务对象进行访问的接口
l 事件:定义了SAP系统中与该业务对象相关的某种行为,通常是状态的改变。事件往往与工作流系统相关联。可通过事件触发工作流或任务。
(1)下图为业务对象类型BUS1001的组件列表:
上图中的关键字段Material.Material即为数据库表MARA中的关键字段:
(2)在浏览某个业务对象类型基本数据时,可以修改Defaults选项卡中业务对象的默认方法和属性,如果对业务对象访问时没有指定其他具体参数,则将执行默认的方法(具体是这样的吗?如何测试?):
(3)在方法列表中,其名称后有绿色标记的方法,表示该方法是通过BAPI实现;如果有“Stop”标识则表示该方法已经过时,有新的替代方法,不应再使用:
(4)双击某个方法(GetDetail),可以查看其名称、版本信息,并可以设定方法的一些特性:
上面General选项卡的各个选项的意义如下:
l Dialog:表示方法中包含用户交互对话,这种类型的方法不能在后台模式中执行
l Synchronous:设定方法的处理为同步模式;否则为异步模式。在工作流系统中,基于异步方法所创建的任务必须包含至少一个终止事件
l Result parameter:设定方法将返回一个参数作为结果。可能结果的值列表可以在Result type选项卡中的参照数据字典类型或对象类型来设定。只有同步方法才能够设定返回结果
l Instance-independent:表示该方法为实例无关的对象类型方法,即并不关联到特定物业的操作,例如Create(创建物料)、Getlist(显示列表)等方法,使用时并不需要指定具体操作的物料代码;而GetDetail等方法就需要在输入参数中设定关键字段,确定所操作的对象实例
Reuslt type选项卡用于设定方法的返回类型,只有选中Result parameter选项后才需要设定该选项卡:
ABAP选项卡中还可以选择业务对象方法的实现方式,具体包括功能模块、BAPI函数、事务、报表等(业务对象方法如果是通过BAPI方法来实现的,则实现方式要选择API function,另外还需要指定对应到的BAPI功能模块,如下图):
双击上图中的BAPI功能函数模块,即可进入到BAPI功能模块的源代码屏幕。该功能模块是一个支持远程调用的功能模块(RFM),其功能是将从数据库中选择物料的数据,并通过表参数返回结果,并在下面第(6)步的业务对象实现程序RBUS1001的方法GetDetail所对应的代码段中调用该BAPI功能函数模块
(5)把光标放在某方法名上,选择Parameters按钮,可以查看方法的输入输出参数设定。对于同步方法可以设定输入、输出参数、返回值以及异常;而对于异步方法则只能设定输入参数:
(6)把光标放在某组件上,选择Program按钮,可以查看该组件在业务对象程序中相关代码段。业务对象BUS1001的系统程序名为RBUS1001,业务对象组件中关键字段、属性的定义,以及方法和事件的实现,都在该程序的代码完成。该程序及其中的代码,一部分是在创建业务对象时自动生成的,一部分是通过手工添加进行完善的。下图为方法Material.GetDetail的代码,因为GetDetail是一个BAPI方法,所以图中的代码段将调用BAPI功能模块BAPI_MATERIAL_GET_DETAIL,而普通的方法(非BAPI)不一定需要通过BAPI功能模块实现:
测试业务对象
(1) 通过SWO1界面,输入业务对象 BUS1001,选择按钮,进入测试界面,此时业务对象还没被实例化,因此只显示与实例无关的属性和方法(即静态属性与方法):
(2) 如果需要测试与实例相关的方法,则需要点击Instance按钮,指定一个物料业务对象实例,即输入特定的物料号,就可以对实例方法进行测试了:
(3) 选择GetDetail方法后面的按钮,并根据需求输入该BAPI方法的Import参数值:
(5) 返回到初始测试页面,并选择Display方法,按同样的步骤进行测试,执行后系统将进入事务MM03界面,该方法不是一个BAPI方法,没有输入输出参数及返回值,而是直接调用一个事务:
BAPI
BAPI是在BOR(业务对象仓库)中为SAP业务对象类型或接口类型定义的特殊方法,通过具有RFC属性的ABAP功能模块(即RFM )来实现,这种和业务对象关联的RFM也称为BAPI功能模块,俗称BAPI。因此,BAPI本意指代业务对象方法,但也常常可以指代其实现的功能模块
SAP业务对象的方法可以通过多种方式实现,BAPI实质上是一种特殊的、支持远程调用的业务对象方法,是通过具有“可远程调用”属性的函数实现
BAPI作为建立在RFC协议之上的、通过业务对象类型进行组织的系统接口,是在业务级别而不是技术层次定义的,因此可作为任意外部系统或应用访问SAP系统的标准途径,具有开放优点。一旦SAP为对象发布一个BAPI,则保持在后续所有软件版本对该BAPI的支持
BAPI:Business Application Process Interface(业务应用编辑接口),它实质上就是一种特殊的RFC,比如修改资产数据的BAPI函数:
RFC(Remote Function Call)不仅是一个函数,也是一个数据通信协议,与外部程序调用
RFC与普通的本地函数(也就是上面第一项:Normal Function Module)不同的是,RFC所有参数只能是传值Pass Value,原因是因为远程调用时,参数值的传递都是值,而不是引用,因为变量的引用都在本地内存中才能引用并指向:
与前面介绍的BDC、CATT、LSMW的应用不同,前三者是通过录制屏幕的方式来实现数据维护,而BAPI则需要通过ABAP程序来调用,只需要向指定的接口中传递数据,即可完成数据的维护操作。当然,不是所业务都提供了BAPI,有的还是需要通过BDC等方式来实现数据的批量维护
ü 它实际上是一种特殊的Remote Function Modules (RFC),在SAP内部组件及非SAP组件之间的技术整合与业务数据交换过程中起很大的作用。SAP通过该标准接口把整个系统链接为一个整体。外部程序可以通过BAPI访问SAP系统中的业务对象、数据、应用
ü 它提供的基于企业目标(Business Object业务对象) 技术的接口应用界面
ü SAP采用了Object-oriented技术,逻辑定义了SAP R/3系统的所有功能目标,并且将所有的目标(Objects) 和BAPIs存储于企业目标库BOR(Business Objects Repository).
ü SAP R/3 企业业务对象的对象类型(Object Type) 相当于对象设计语言中类(Class) 的概念,其定义结构由以下几部分组成:基本数据、接口界面、键(Key Fields)、方法(Methods)、特征(Attributes)、事件(Events)
ü BAPI支持同步、异步的数据通信过程
ü 通过基于RFC协议实现的BAPI接口,可以从应用层直接对SAP业务对象进行访问
ü BAPI建立在RFC协议基础上,外部语言需要进行RFC调用,即通过外部RFC接口来调用BAPI
ü 在第三方开发环境中,我们既能够直接访问BAPI,也能够通过RFC访问BAPI。在面向对象语言中(如:Java,C++),我们既直接访问BAPI也能够通过RFC访问BAPI,而在非面向对象语言中(如:C),只能利用RFC访问BAPI
BAPI与ABAP OO
BAPI的查找
通过业务对象创建器SWO1查看BAPI
具体操作可查看前面SAP业务对象中前部分SWO1的讲解
通过BAPI浏览器查找BAPI(BAPI)
事务码BAPI:
Documentation选项卡中的说明文档提供了使用相关BAPI的详细说明。
可以通过业务对象名来查找某个业务对象类型(如下图可以直接找出业务对象类型为 Material 的业务对象):
直接查找BAPI函数
BAPI对应的功能模块命名规则BAPI_<bo>_<method>(<bo>即为业务对象名),因此可以直接在SE37中通过前缀BAPI加对象名称或方法名称作为关键字,快速查找一个BAPI功能模块函数。如检索 BAPI*Material*Get*
查找某个事务码相对应的BAPI
如果只知道事物代码,可以通过下面的方式查询相应的BAPI。例如找创建销售(物料模板根据此方法好像找不出)订单的BAPI,我们知道事物代码是VA01:
1. 我们进入VA01 界面,找到system ? status
2. 在事物代码位置上双击(注:不是程序上双击),找到PACKAGE VA
3. 用SE80打开包 VA ,或点击 Display Object List按钮直接进入到SE80对象列表:
4. 打开业务工程(引擎)——业务对象类型。根据我们的业务需求。我们要找销售订单的创建,所有BUS2032 销售订单的可能性最大。
5. 双击打开业务对象类型BUS2032,寻找和创建销售订单名字相同的方法这里我们要找的就是SalesOrder.CreateFromDat2:
双击SalesOrder.CreateFromDat2 行,在弹出的窗口中找到 ABAP 选项卡,如果单选按钮是 API功能,则名称一栏即为我们要找BAPI,如果是函数模块即为一个FM,即BAPI_SALESORDER_CREATEFROMDAT2:
注:上面是SalesOrder为业务对象名,而BUS2032为业务对象类型名:
根据BAPI函数查找对应的业务对象
BAPI 函数跟业务对象的关系存储在表SWOTLV中,对于一个业务对象,除了函数外,还存储了一些其它信息。这个表的 ABAPNAME 字段存储的就是函数名称,而 LOBJTYPE 字段则存储了业务对象类型名称。这样,当我们找到一个 BAPI 函数后,就可以到这个表里查找它对应的业务对象了:
SAP 在给业务对象命名的时候仅有一部分用了缩写命名法,可以从缩写中猜测到业务对象的作用。接下来就是找表TOJTB,它的 NAME 字段存储了业务对象类型名称,而 EDITELEM 则是业务对象,这个描述就是事务码BAPI 中看到的名称。此外,从它的文本表 TOJTT 中还可以得到关于这个业务对象的详细描述:
调用BAPI
事务性
BAPI功能模块是BAPI方法的具体实现。
根据事务的ACID原则,一个独立的BAPI实现必须具有事务性,同时,BAPI事务模型还必须允许开发者在调用多个BAPI时可以将它们绑定到同一个LUW上。因此,如果同时调用几个BAPI,开发者需要在程序中进行的事务控制,决定何时执行数据库提交或回滚操作;而BAPI内部则通常不包含COMMIT WORK和ROLLBACK WORK命令
操作多个BAPI时必须遵循以下原则(注:都是指在外部程序即主调程序中,而非BAPI功能模块内部):
l 如果有更新操作的BAPI,如创建、修改或删除一个业务对象实例,则对该实例进行另外的读取操作的BAPI只能访问上一个COMMIT WORK执行后的最新数据
l 在同一个LUW中,不能对同一个业务对象实例时行超过一次的更新操作。例如,不允许在一个LUW中创建一个新实例,随后就修改它。但可以创建多个相同的类型的不同实例
在BAPI内部,数据库更新操作必须通过同步或异步的更新过程实现,因为否则可能出现不必要的数据库提交过程,从而破坏了BAPI调用的ACID原则。同样原因,BAPI内部也不能触发新的LUW,因而其内部程序代码中不能包含以下命令:
l CALL TRANSACTION
l SUBMIT REPORT AND RETURN
因此,BAPI事务中的数据库提交和回滚必须在主调程序中通过调用SAP标准业务对象BapiService(对象类型为SAP0001)的BAPI方法BapiService.TransactionCommit(此BAPI方法实际上还是通过调用BAPI函数BAPI_TRANSACTION_COMMIT来实现的)和BapiService.TransactionRollback(此BAPI方法实际上还是通过调用BAPI函数BAPI_TRANSACTION_ROLLBACK来实现的)来完成。在R/3 4.5之前,可以使用远程功能模块BAPI_TRANSACTION_COMMIT和BAPI_TRANSACTION_ROLLBACK完成相同的功能
在外部程序调用BapiService.TransactionCommit方法前,外部程序调用BAPI时并不触发数据库提交
对于BAPI的操作都要用BAPI_TRANSACTION_COMMIT来提交的,所以要判断BAPI的执行情况的返回值(参数RETURN),如果有错误要用BAPI_TRANSACTION_ROLLBACK取消所做的操作。建议在调用BAPI_TRANSACTION_COMMIT函数进行提交BAPI操作时,加上wait参数(如在该函数调用处后面代码需要读取前面刚提交的数据时),这样会减少某些错误:
CALL FUNCTION ‘BAPI_TRANSACTION_COMMIT‘
EXPORTING
wait = ‘X‘.
WAIT为X时,会执行COMMIT WORK AND WAIT语句,否则执行COMMIT WORK语句
在ABAP中调用BAPI函数
BAPI调用成功与否一般通过RETURN参数返回(约定俗成)
因为需要支持事务性RFC调用,所以BAPI功能模块中不包含异常处理参数(以及Changing也是没有的,只有Import、Export、Tables参数)。其成功调用或出错信息通过Export中的特定输出参数RETURN返回。该参数的数据结构可以参照数据字典结构BAPIRETURN、BAPIRETURN1、BAPIRET1、BAPIRET2或BAPIRET2_FIX等来定义,各种RETURN结构中的通用字段包括:
l TYPE,消息类型,如S、E、W、I
l ID,消息类型
l NUMBER,消息编号
l MESSAGE,消息文本
l MESSAGE_V1、MESSAGE_V2、MESSAGE_V3、MESSAGE_V4,消息变量
在BAPI返回结果时,必须通过与所调用的BAPI中RETURN参数相同类型的程序变量接收该参数返回值,并查看其结果。如果BAPI调用过程成功完成,RETURN字段可能为空,也可能在TYPE字段中包含S值,这需要在调用程序自行判断处理
实例:通过BAPI修改资产数据
在BDC录制时,只需要输入资产编号就可以从系统自动抓出该资产分类,而该BAPI有三个参数是必输入的:公司代码、资产编码、资产分类,在调用BAPI时只能通过资产编号与公司代码到相应表(ANLA)中查找分类了。
BAPI的参数结构有个特点:一般会将类似的字段放在同一个结构中,同时,还会存在一个与该结构名类似(后面以X结尾)标识结构,该标识结构中的字段名与赋值的结构中的字段名一致,但是其字段类型只是一个长度为1的字符,用于标识某个字段的数据是否需要通过BAPI来变更,例如:资产中的“一般数据”都通过BAPI的GENERALDATA字段来维护,若使用GENERALDATA接口,则需要传递GENERALDATAX结构。如这里要修改资产描述,资产描述对应的字段是GENERALDATA-DESCRIPT,若该字段被赋值,那么必须同时赋值GENERALDATAX-DESCRIPT=X,该字段才会被修改
TYPE-POOLS:truxs.
DATA:it_raw TYPE truxs_t_text_data.
DATA: companycode LIKE bapi1022_1-comp_code VALUE ‘0005‘,
asset LIKE bapi1022_1-assetmaino VALUE ‘11000001‘,
subnumber LIKE bapi1022_1-assetsubno VALUE ‘0‘,
generaldata LIKE bapi1022_feglg001 ,
generaldatax LIKE bapi1022_feglg001x,
return LIKE bapiret2.
START-OF-SELECTION.
generaldata-descript = ‘资产描述‘.
generaldatax-descript = ‘X‘.
generaldata-descript2 = ‘资产主号说明‘.
generaldatax-descript2 = ‘X‘.
CALL FUNCTION ‘CONVERSION_EXIT_ALPHA_INPUT‘
EXPORTING
input = asset
IMPORTING
output = asset.
CALL FUNCTION ‘CONVERSION_EXIT_ALPHA_INPUT‘
EXPORTING
input = subnumber
IMPORTING
output = subnumber.
CALL FUNCTION ‘BAPI_FIXEDASSET_CHANGE‘
DESTINATION ‘NONE‘"根据设定的目标值,可以远程调用,也可本地调用
EXPORTING
companycode = companycode
asset = asset
subnumber = subnumber
generaldata = generaldata
generaldatax = generaldatax
IMPORTING
return = return.
IF return-type <> ‘S‘.
CALL FUNCTION ‘BAPI_TRANSACTION_ROLLBACK‘.
ELSE.
CALL FUNCTION ‘BAPI_TRANSACTION_COMMIT‘
EXPORTING
wait = ‘X‘.
ENDIF.
WRITE: / return-type , return-message.