博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[AX]AX2012 AIF(二):文档服务编程模型
阅读量:6717 次
发布时间:2019-06-25

本文共 5915 字,大约阅读时间需要 19 分钟。

一个完整的文档服务包含很多对象,以Customer服务为例,它包含以下对象:

  • 查询AxdCustomer:这个query的顶层表为CustTable,其下Datasource包含表DirParty,DirParty下的Datasource则再包含表DirPersonName、表DirOrganizationName、视图DirPartyContactInfoView、视图DirPartyPostalAddressView。这个Query定义了服务所用的所有相关数据的数据模型。
  • 文档服务类CustCustomerService:这是直接提供服务的类,它包含Create、Delete、find、findKeys、getKeys、getChangedKeys等对外服务的方法,这些方法使用特定的特性标注,比如Create方法使用了[AifDocumentCreateAttribute, SysEntryPointAttribute(true)]标注,AifDocumentCreateAttribute指出这个方法是文档服务的创建方法,这个特性不是必须的,主要用途是在使用metadata服务时我们可以根据这个特性列举出所有删除记录的服务操作;SysEntryPointAttribute特性指示是否进行授权检查,所有的服务操作必须指定这个特性,其参数true表示要对调用用户检查是否有权操作该方法涉及到的数据表,false则不执行这个检查。文档服务类服务的具体操作都交由其继承的基类AifDocumentService具体操作,比如read()方法内部调用的是AifDocumentService.readList()方法。
  • 数据对象类CustCustomer、CustCustomer_CustTable、CustCustomer_DirParty、CustCustomer_DirParty_DirPerson等:这些类描述了查询AxdCustomer定义的数据模型,CustCustomer直接对应Query AxdCustomer,它是数据对象类的最顶层,它依靠其他数据类CustCustomer_CustTable、CustCustomer_DirParty等。CustCustomer从AifDocument继承,后者又从AfStronglyTypedDataContainer继承,而AfStronglyTypedDataContainer又从AifXmlSerializable继承,由它描述了XML消息定义的一个文档,所以我们在read()服务操作方法中看到的返回值就是这个类的一个实例。其他的数据对象类都直接从AfStronglyTypedDataContainer继承,所以数据对象类包括CustCustomer都实现一系列的existsXXX()方法,这些方法判断某个字段是否存在,调用基类的exists()方法;一系列parmXXX()方法,获取某个字段的值或者下层的数据对象实例;createXXX()方法,创建并返回其下层的数据对象类实例列表,比如CustCustomer.createCustTable()返回包含CustCustomer_CustTable类实例的列表。
  • 文档类AxdCustomer:文档类的作用是封装涉及到的多个表业务逻辑,这样外部调用应用不需要确切的知道如何操作底层数据库表。Axd类实现AifServiceable接口,这里的AxdCustomer不是直接实现这个接口,而是从AxBase扩展,后者实现AifServiceable接口。总体上来讲Axd类实现到XML的序列化及反序列化,生成XSD数据Schema,控制内部表的生命周期等,由它间接的操作下面要讲到的AxXXX表类。Axd类包含的方法很多,更详细的介绍可以参见,这里列举几个实现接口AifServiceable比较重要的方法:getName()返回文档的名称,这是XML文档的根标签的名称;getSchema()返回数据Schema XSD;getActionList()返回文档支持的操作列表,比如AxdCustomer支持findList、read、readList等操作。
  • 表类AxCustTable、AxDirPartyTable等:这组类以Ax<Table>方式命名,和文档类协同工作,同样封装数据表业务逻辑,从AxInternalBase继承,代表了AOT中的某个表。Ax<Table>类不是必须的,在使用AIF Document Wizard创建新的文档服务时,勾选了“Generate AxBC Classes”才会创建这些类。如果使用Ax<Table>类,可以在文档级别使用“Value mapping” form来映射数据表字段。Ax<Table>内部使用类AxdBaseRead、AxdBaseCreate读写数据库表,不使用Ax<Table>的情况则可以在Axd文档类中使用AxCommon读写数据库表。需要注意的如果在服务的Query中添加了一个新的表,相应的Ax<Table>类不会自动生成,这时候可以使用Update document service”工具的“Regenerate data object classes”和“Update AxBC classes”选项重新生成或者更新Ax<Table>类。Ax<Table>类和AOT中的表是一一对应的,由它直接操作表数据,具体功能包括生成表字段的默认值、按照正确的顺序设置表字段值、维护验证关联表数据的完整性、字段值映射比如从供应商料名映射到内部料名、错误处理等,需要注意的是Ax<Table>不会验证是谁在操作数据表,用户验证要放到前面提到的服务类。

看完相关的类和对象,在开始后续的问题前,我们先来看看Schema XSD是如何生成的。数据对象类继承自AifDocument(顶级对象),也可能是AfStronglyTypedDataContainer,AfStronglyTypedDataContainer有一个方法叫做getSchema()返回Schema XSD;而AifDocument是继承自AfStronglyTypedDataContainer,它重载了getSchema()方法,它会创建对应Axd类的实例,调用前面提及的Axd类的getSchema()返回Schema XSD。实际上无论是AifDocument.getSchema()还是AfStronglyTypedDataContainer.getSchema(),它们最终都使用AxdBaseGenerateXSD.generate()生成Schema XSD。这里不深入讨论是如何生成XSD的,需要知道的是以上方法会枚举文档定义的Query,从Query中查找Datasource字段生成相应的XML标记,文档Query必须只有一个根Datasource,隐藏或者禁止的字段被排除在外,XML的根元素名称来自于Axd<document>去掉Axd前缀。我们可以用下面的Job从代码生成相应文档服务的XSD:

static void GenerateXSDSchema_Customer(Args _args){    CustCustomer        customer;    XML                 xml;    XMLDocument         xmlDocument;    FileName            fileName;    ;    // Instantiate the class.    customer = new CustCustomer();    // Get the document class schema.    xml =customer.getSchema();    xmlDocument = XMLDocument::newXML(xml);    // Save the schema to a file.    fileName = "c:\\XSDSchema_Customer.xsd";    new FileIoPermission(fileName, 'rw').assert();    xmlDocument.save(fileName);    CodeAccessPermission::revertAssert();}

在生成的Schema中我们可以看到AxdCustomer类被映射为complexType类型,其下包含的元素是从AxdCustomer的parmXXX方法去掉parm而来;Query中的表Custtable也映射为complexType类型,名称为AxdEntity_CustTable,包含的元素来自于表字段,只有那些包含在AxCustTable.parmXXX方法的字段才会出现在XSD中。更详尽的字段类型到XSD的单元的映射关系参见。要说明的是上面得到的文档服务的完整XSD,而我们在端口配置窗口中“View schema”看到的XSD是完整XSD的子集,在“Document data policies”窗口我们可以手工使能或者禁止某个字段,这只是对当期所配置的AIF端口有效。

XSD描述了XML消息的格式,下面是CustCustomerService.read操作得到的XML序列化结果样例(省略部分内容):

-
-
{93FE7B5F-99E6-45D6-BAA5-654699EFF0EA}
http://schemas.microsoft.com/dynamics/2008/01/services/CustomerService/read
{E983D78F-0011-47B7-8716-F8B64D120EF6}
- -
-
Original
DMO
2012-04-19T19:42:40Z
AsOf
-
<_DocumentHash>261dcc95694f19ee9010b1866237b4a2
4503
Always
No
14D1%
......
WebEntered
-
En-us
3 Company
3
1310
5637145091
1
-
522 West 5th Street New York, NY 10032 US
New York
....
None
-
3 Company
5637144581
1
2009-06-13T00:17:00Z
2154-12-31T23:59:59Z

消息包括封皮Envelope和Header段,Header段的Action指定操作的名称。有几点需要说明,注意到Axd类parmXXX被序列化到XML;Query中的表加上了class="entity"属性;如果使用了Ax<Table>,只有Ax<Table>.parmXXX方法指定的内容被序列化,并且由它来读取验证数据,否则数据直接从数据库表读出Query中指定的字段。

我们已经知道文档服务的具体操作是在文档服务类中实现,标准的文档服务操作包括create、delete、find、findKeys、read、update、getKeys、getChangedKeys。在AOT的Services节点下我们可以新建一个Service来引用这些操作,进而在出入站端口中使用。当然不是每一个文档都需要实现上述所有的标准服务,此外我们还可以添加自定义的服务操作,这些自定义服务操作方法必须定义为public,如果参数或者返回值是个对象类,那么这个对象类必须实现AifXmlSerializable接口,如果不是对象类则只有以下几种元类型被支持:str、 date、 utcdatetime、 guid、 int、 int64、 enum、real、void。如何创建一个自定义服务可以参见。

在findKeys、update、read等方法中用到类AifEntityKeyList,它表示的是一个键值对,比如我们要读取一个Customer的信息,传入的键值对可能是AccountNum=5407。如果我们在自定义的方法中需要返回大量数据,可以考虑只返回记录的键值对,然后再用read方法根据键值对取出实际的记录数据,这有助于提高性能。

后续还有更多关于文档服务的内容......

转载于:https://www.cnblogs.com/duanshuiliu/archive/2013/01/30/2882581.html

你可能感兴趣的文章
windows系统下,安装多个版本的jdk,java -version
查看>>
php 分页查询
查看>>
ubuntu 下命令行格式化 U盘 (转载)
查看>>
Java集合--TreeSet
查看>>
BurpSuite系列----Extender模块(扩展器)
查看>>
CSS media queries
查看>>
session的序列化、钝化、活化
查看>>
PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化)/约束类型/魔术方法小结...
查看>>
==与===的区别
查看>>
JS 在指定数组中随机取出N个不重复的数据
查看>>
软件开发模型
查看>>
Windows Store App下代码加载page resource和resw文件里的string
查看>>
数据结构基本知识点总结
查看>>
【翻译】前景img-sprites, 高对比模式分析
查看>>
进程和线程的一个简单形象的解释
查看>>
The road to learning English-Grammar
查看>>
Python多线程编程之多线程加锁
查看>>
shell报错:-bash: [: ==: 期待一元表达式 解决方法 ([: ==: unary operator expected)
查看>>
opengl 杂记
查看>>
兼容MIUI5和MIUI6的开启悬浮窗设置界面
查看>>