[AX]AX2012 AIF(二):文档服务编程模型

一个完整的文档服务包含很多对象,以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类包含的方法很多,更详细的介绍可以参见http://msdn.microsoft.com/EN-US/library/aa862063.aspx,这里列举几个实现接口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的单元的映射关系参见http://msdn.microsoft.com/EN-US/library/aa636469.aspx。要说明的是上面得到的文档服务的完整XSD,而我们在端口配置窗口中“View schema”看到的XSD是完整XSD的子集,在“Document data policies”窗口我们可以手工使能或者禁止某个字段,这只是对当期所配置的AIF端口有效。

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

  <?xml version="1.0" encoding="UTF-8" ?> 
- <Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
- <Header><MessageId>{93FE7B5F-99E6-45D6-BAA5-654699EFF0EA}</MessageId> <Action>http://schemas.microsoft.com/dynamics/2008/01/services/CustomerService/read</Action> <RequestMessageId>{E983D78F-0011-47B7-8716-F8B64D120EF6}</RequestMessageId> </Header>
- <Body>- <MessageParts xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">- <Customer xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/Customer"><DocPurpose>Original</DocPurpose> <SenderId>DMO</SenderId> <ValidAsOfDateTime>2012-04-19T19:42:40Z</ValidAsOfDateTime> <ValidTimeStateType>AsOf</ValidTimeStateType> - <CustTable class="entity"><_DocumentHash>261dcc95694f19ee9010b1866237b4a2</_DocumentHash> <AccountNum>4503</AccountNum> <AccountStatement>Always</AccountStatement> <Blocked>No</Blocked> <CashDisc>14D1%</CashDisc> ......<WebSalesOrderDisplay>WebEntered</WebSalesOrderDisplay> - <DirParty xsi:type="AxdEntity_DirParty_DirOrganization" class="entity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><LanguageId>En-us</LanguageId> <Name>3 Company</Name> <NameAlias>3</NameAlias> <PartyNumber>1310</PartyNumber> <RecId>5637145091</RecId> <RecVersion>1</RecVersion> - <DirPartyPostalAddressView class="entity"><Address>522 West 5th Street New York, NY 10032 US</Address> <City>New York</City> ....<ABC>None</ABC> - <OrganizationName class="entity"><Name>3 Company</Name> <RecId>5637144581</RecId> <RecVersion>1</RecVersion> <ValidFrom>2009-06-13T00:17:00Z</ValidFrom> <ValidTo>2154-12-31T23:59:59Z</ValidTo> </OrganizationName></DirParty></CustTable></Customer></MessageParts></Body></Envelope>

消息包括封皮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。如何创建一个自定义服务可以参见http://msdn.microsoft.com/EN-US/library/aa607052.aspx。

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/462780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装sql server 2000时,提示:以前的某个程序安装已在安装计算机上创建挂起的文件操作,需重起...

打开注册表编辑器&#xff0c;在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager中找到PendingFileRenameOperations项目&#xff0c;并删除它。这样就可以清除安装暂挂项目。 方法二&#xff1a; 1、添加/删除程序中彻底删除sql server。 2、将没有删除…

iOS 打包.framework(包括第三方、图片、xib、plist文件)详细步骤及需要注意的地方...

https://www.cnblogs.com/yk123/p/9340268.html // 加载自定义名称为Resources.bundle中对应images文件夹中的图片// 思路:从mainbundle中获取resources.bundleNSString *strResourcesBundle [[NSBundle mainBundle] pathForResource:”Resources” ofType:”bundle”];// 找到…

MySQL中innodb_page_cleaners详解

innodb_page_cleaners是MySQL中的刷脏线程个数&#xff0c;它的值等于innodb_buffer_pool_instances的值&#xff0c;如果innodb_page_cleaners的值大于innodb_buffer_pool_instances的值&#xff0c;那么自动的将innodb_page_cleaners调整为与innodb_buffer_pool_instances的值…

uiimagepickerviewcontroller

if(0buttonIndex) { if (![UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) { UIAlertView *alert [[UIAlertView alloc] initWithTitle:"" message:"当前设备不支持拍照功能" delegate:nil cancelButtonTitl…

关于CString的=操作符

检查自已的代码时&#xff0c;发现一个比较弱智的错误&#xff0c;是关于转码的&#xff0c;和CString的操作符有关。 为了能简单重现&#xff0c;我模拟了一下代码&#xff1a; //未有UNICODE或_UNICODE定义 USES_CONVERSION; CString sTest(_T("test中文")); s…

分布式锁的几种使用方式(redis、zookeeper、数据库)

三种方案的比较 从理解的难易程度角度&#xff08;从低到高&#xff09; 数据库 > 缓存 > Zookeeper从实现的复杂性角度&#xff08;从低到高&#xff09; Zookeeper > 缓存 > 数据库从性能角度&#xff08;从高到低&#xff09; 缓存 > Zookeeper > 数据库从…

SQL优化准则

1. 在长时间运行的查询和短查询中使用事务 如果预期有一个长时间运行的查询&#xff0c;并且有大量的数据输出时&#xff0c;开发者就应该在BEGIN TRAN 和END TRAN之间使用事务。 这样事务会在缓冲区缓存为独立事务&#xff0c;并会被分配特定内存&#xff0c;以此来提高处理…

C语言库函数--strstr()

原型&#xff1a;extern char *strstr(const char *str1, const char *str2); 需要包含的头文件&#xff1a;#include <string.h> 作用&#xff1a;用于判断字符串str2在字符串str1中第一次出现的位置。如果没有找到则返回NULL&#xff0c;找到了则返回str1中的位置。 …

《离散数学》双语专业词汇表 名词术语中英文索引

《离散数学》双语专业词汇表 set&#xff1a;集合 subset&#xff1a;子集 element, member&#xff1a;成员&#xff0c;元素 well-defined&#xff1a; 良定&#xff0c;完全确定 brace&#xff1a;花括号 representation&#xff1a;表示 sensible&#xff1a; 有意义的 rat…

less is more,so 只记 less

less 文件名 1.Enter键  &#xff1a;向下翻一行 2.空格键   &#xff1a;向下翻一屏 3.j键    &#xff1a;想下翻一行 4.k键    &#xff1a;向上翻一行 5.f键    &#xff1a;向下翻一屏 6.b键     &#xff1a; 向上翻一屏 7.d键    &#xff1a;向…

预祝大家2011农历新年快乐,宏“兔”大展,心想事成~

预祝大家2011农历新年快乐&#xff0c;宏“兔”大展&#xff0c;心想事成&#xff5e; 又是一年新年到&#xff0c;预祝大家2011农历新年快乐&#xff0c;宏“兔”大展&#xff0c;心想事成&#xff5e; _____________________________________________________ 以下是附带的……

MySQL中的表压缩功能

MySQL版本&#xff1a;8.0.22 os&#xff1a;linux ubuntu 语言&#xff1a;c、c 在MySQL中支持3种类型的表压缩&#xff0c;依次为&#xff1a;传统压缩、TPC压缩、字典压缩。 第一种&#xff1a;传统压缩 传统的表压缩方式是在MySQL5.0.7之前使用的&#xff0c;现在已经废…

net core体系-web应用程序-4asp.net core2.0 项目实战(1)-11项目日志解决方案

本文目录1. Net下日志记录2. NLog的使用 2.1 添加nuget引用NLog.Web.AspNetCore 2.2 配置文件设置 2.3 依赖配置及调用 2.4 日志类型介绍 2.5 产生的日志文件3. 基于Microsoft.Extensions.Logging封装 3.1 添加引用Microsoft.Extensions.Logging 3.2 实现…

strcasecmp()--忽略大小写比较字符串

strcasecmp()的功能是&#xff1a;忽略大小写比较字符串 头文件 #include <strings.h> 函数原型&#xff1a;int strcasecmp(const char *s1, const char *s2); 函数功能: 用来比较参数s1和s2字符串&#xff0c;比较时会自动忽略大小写的差异。 返回值: 若参数字符串…

NDK 获取android的imei和serial number

1&#xff0c;获取imei int setAndroidDeviceID(JNIEnv *env, jobject obj,jobject mContext) {if(mContext 0){return -1;}jclass cls_context (*env)->FindClass(env, "android/content/Context");if(cls_context 0){return -1;}jmethodID getSystemService …

《JS高级程序设计》PART3.对象基础

3.2对象应用 对象废除&#xff1a;如果一个对象有2个及以上引用&#xff0c;则要正确的废除该对象&#xff0c;必须将其所有引用都设置为null。 js和java一样&#xff0c;有垃圾回收机制&#xff0c;会自动收回已无引用指向的对象。 早绑定和晚绑定 绑定&#xff1a;把对象的…

python迭代-如何对迭代器做切片操作

如何对迭代器做切片操作 问题举例 读取某个文件内容的100~300行内容&#xff0c;我们是否可以使用 类似列表切片的方式得到一个100~300行文件内容的生成器 分析 列表的切片操作其实是在重载方法__getItem__方法 可以通过file.readlines()后再做切片&#xff0c;内存会加载整个文…

如何让linux服务器同步互联网时间

今天在工作中需要搭建一个数据库集群s1&#xff0c;需要将节点A、节点B和节点C都加入集群&#xff0c;先在A节点上创建集群&#xff0c;然后将B和C节点加入到集群&#xff0c;但是在B和C加入到集群之前&#xff0c;会判断B与A、C与A的时间戳是不是在设置的2s~5s内&#xff0c;如…

Conda常见命令

Anaconda,Miniconda,Conda,Pip的区别&#xff1a; Anaconda&#xff1a;用于科学计算的python发行版&#xff0c;里面预装好了conda&#xff0c;某个版本的python&#xff0c;众多packages,科学计算工具等。Anaconda利用工具/命令conda来进行package和environment的管理&#x…

MySQL一张innodb表列个数的限制和engine的选择

在MySQL innodb存储引擎中&#xff0c;一张表中列的个数最大为4096。 其中在MySQL中&#xff0c;创建表时可以任意指定engine的类型&#xff0c;但是&#xff0c;考虑到join、union、union all等复杂的场景时&#xff0c;尽量每张表都用统一的engine。