在对文档服务编程模型了解之后,创建自定义的文档服务就显得相对简单了,基本步骤是:
- 创建Query,以AxdXXX命名,加入一个表作为根Datasource,在其Datasource下可以加入子数据源,设置好表之间的relation。
- 从开发Workspace的菜单Tools > Application Integration Framework > Create Document Service启动Wizard工具,或者直接在AOT中右键点击Query,选择Add-ins>AIF document service wizard。在Wizard工具中需要设置Document name、Service class name、Document object class name、Axd class name等信息,选择需要生成的标准文档服务操作,以及是否生成Ax<Table>类,完成后Wizard工具会给自动创建一个Project,工程下包含所需的文档服务类、数据对象类、Axd类、宏定义、Service AOT节点和一个用于生成文档XSD的Job。
- 创建出入站端口部署文档服务。
试图编译自动创建的工程,你会得到一些错误和Todo消息,错误来自于Ax<Table>的cacheObject和cacheRecordRecord两个方法。打开这两个方法,你会发现函数函数中的代码都注释掉了,而函数声明中的CacheRecord是无效的。CacheObject用来缓存后续需要用到的对象,函数的名称根据需要重新命名,比如AxSalesLine的axSalesTable方法,它缓存一个axSalesTable类的实例,在其他方法中(比如AxSalesLine的setCustAccount)使用这个方法直接得到这个axSalesTable实例,如果需要这个函数把函数中的cacheObject替换成你的类名称并去掉注释。如果不需要缓存任何对象,直接删掉这个函数。cacheRecordRecord作用也是一样,只不过它用来缓存一条表记录,比如AxSalesLine的inventTableRecord方法,同样如果不需要就删掉好了。
在输出的Toto消息很多中除了很多关于设置Label和Description的提示外,有一些是值得关注的:
- Axd类的prepareForSaveExtended()方法中有一条注释是“//TODO Put validating code for SalesPickTable here”,这是提示添加自定义的数据验证,比如检查重复的数据记录。MSDN讲重载prepareForSave()方法来加入自定义的验证,实际上AxdBase的prepareForSaveExtended()方法会调用prepareForSave方法,而我们的Axd类重载了prepareForSaveExtended方法,重载后不会再调用prepareForSave方法,所以MSDN的说法应该是有误,直接在Axd类的prepareForSaveExtended方法验证数据就好了。
- Axd类的prepareForSaveExtended()方法还有一条注释是“//TODO: Add code here to ensure that required fields specified in the initMandatoryFieldsMap method are sent in by the service caller.”,这也是提示要对入站数据检查是否包含那些设定为强制的字段数据。initMandatoryFieldsMap()是AxdBase的一个方法,它默认添加DirPartyPostalAddressView的一些字段为强制,在你的Axd类中如果需要添加其他的一些未在Ax<Table>类中设为强制的字段或者parm方法,可以这样来使用:
protected void initMandatoryFieldsMap() { super(); this.setParmMethodAsMandatory( classnum(AxdSalesOrder), methodstr(AxdBase,parmDocPurpose)); this.setParmMethodAsMandatory( classnum(AxSalesLine), methodstr(AxSalesLine,parmSalesQty)); this.setTableFieldAsMandatory( tablenum(SalesLine), fieldstr(SalesLine,SalesUnit)); }
AxdBase.setParmMethodAsMandatory()设置Axd类的某个parmXXX方法为强制,AxdBase.setTableFieldAsMandatory()则是设置表的某个字段为强制。
- 另外一些Todo是在Axd类的getConstraintList()方法,包括验证表、设置constraint type、constraint id。这个方法添加一些AifConstraint()的实例到AifConstraintList列表,注释说明是for internal use的,没有找到更多有用的信息来判断这个Constraint列表的具体作用。AxdCustomer的GetConstraintList()是这样的:
public void getConstraintList(Common _curRec, AifConstraintList _constraintList) { AifConstraint aifConstraint = new AifConstraint(); CustTable custTable; ; if (_curRec.TableId != tablenum(CustTable)) { throw error(strfmt("@SYS23396",funcname())); } custTable = _curRec ; aifConstraint.parmType(AifConstraintType::Customer); aifConstraint.parmId(custTable.AccountNum); _constraintList.addConstraint(aifConstraint) ; }
这里用到的AifConstraintType枚举类型包含NotSet、Customer、Vendor、NoConstraint、Warehouse,既然不知道它的具体作用,不妨保持原有代码,即添加一个AIFConstraintType::NoConstraint的对象到列表。
除了以上自动创建代码中的问题,在创建自定义文档服务MSDN还提示需要注意的一些问题:
- 在出站调用中,Axd类的initQueryFromEntityKey()方法会被调用,它从对象键值构建一个数据库查询,比如AxdPurchaseRequisition,我们需要额外检查采购订单是否已经被关闭,所以在AxdPurchaseRequisition.initQueryFromEntityKey()方法中有对应的订单状态检查。
- Ax<Table>默认不会验证数据,需要调用Ax<Table>.validateInput(true)启用数据验证。
- 如果文档数据中有引用到DocuRef表,建议是只使用文本格式的Note类型以防止数据中包含恶意代码,可以调用AxDocuRef类来验证附属文档类型。
- 对于入站文档不建议直接生成业务交易,除非来源确信可靠,否则最好是先生成Journal,手工过账后生成正式的交易记录,以避免来历不明的文档在系统中生成不正确的信息。
更多内容参见http://msdn.microsoft.com/en-us/library/aa856656.aspx。