AIF文档服务的Update操作用来更新系统数据,支持全部更新(Full update)和部分更新(Partial update)两种类型。
- Full update-这种更新方式使用新的数据替换已经存在的文档数据,提交到AIF的数据被认为是个完整的文档包含所有的字段,效果等同于删除掉原记录重建,但是主键保持不变,XSD允许但不包含在提交数据中的字段依照其数据类型被清除,XSD不允许因而无法提交的字段会被重设为对应默认值。
在消息头中指定Update Action并且主体包含记录上不不带任何更新属性、或者消息头中指定update action并且顶级记录带有replace属性,这两种情况下将执行全部更新。
对于包含子数据的文档比如销售订单需要注意几种情况:
-
- 销售订单只有一个订单行,如果提交的数据包含销售订单数据、一个和数据库中匹配的销售订单行数据、一行和数据库中不匹配的订单行数据,使用全部更新会更新销售订单、更新匹配的销售订单行、同时用新数据创建一个新的订单行。
- 销售订单有三个订单行,提交的数据包含销售订单数据、两个和原有订单行匹配订单行数据,使用全部更新会更新销售订单、两行匹配的原有订单行,而原有的不匹配的第三行订单行将被删除,这是要特别注意的。
Update操作带两个参数,一个是AifEntityKeyList对象,指定要更新的数据文档的键值,比如销售订单行,另外一个参数是顶层的数据对象,比如销售订单服务的SalesSalesOrder对象,因此在我们提交的XML更新操作销售中也会包含这两部分内容。一个更新销售订单的XML消息类似(省略部分内容):
<?xml version="1.0" encoding="utf-8"?> <Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message"> <Header> <MessageId></MessageId> <Action>http://schemas.microsoft.com/dynamics/2008/01/services/SalesOrderService/update</Action> <ConversationId></ConversationId> </Header> <Body> <MessageParts xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message"> <EntityKeyList xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList"> <EntityKey xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey"> <KeyData> <KeyField> <Field>SalesId</Field> <Value>00016_036</Value> </KeyField> </KeyData> </EntityKey> </EntityKeyList> <SalesOrder xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/SalesOrder"> <DocPurpose>Original</DocPurpose> <SenderId>dat</SenderId> <SalesTable class="entity"> <_DocumentHash>820acb9d4e266e791f5069edd7bd3d39</_DocumentHash> ...删除部分数据... <CurrencyCode>EUR</CurrencyCode> <CustAccount>4005</CustAccount> <CustGroup>40</CustGroup> <Deadline>2002-03-30</Deadline> <SalesLine class="entity"> <CustAccount>4005</CustAccount> <CustGroup>40</CustGroup> ...删除部分数据... <InventDimId>00001_060</InventDimId> <ItemId>OL-1500</ItemId> <Name>Office Lamp 1500 2-tubes</Name> <PalletTagging>No</PalletTagging> <PriceUnit>1.00</PriceUnit> <ProjCategoryId>Lamps</ProjCategoryId> <QtyOrdered>200.00</QtyOrdered> <RecId>5637144590</RecId> <RecVersion>406348234</RecVersion> <RemainInventPhysical> 200.00 </RemainInventPhysical> <RemainSalesPhysical>200.00</RemainSalesPhysical> ...删除部分数据... <TaxItemGroup>full</TaxItemGroup> <InventDim class="entity"> <inventDimId>00001_060</inventDimId> <InventLocationId>GW</InventLocationId> <InventSiteId>S1</InventSiteId> <RecId>5637144576</RecId> <RecVersion>1</RecVersion> </InventDim> </SalesLine> </SalesTable> </SalesOrder> </MessageParts> </Body> </Envelope>
消息中包含EntityKeyList节,指定要更新的订单号,SalesOrder节则是完整的销售订单信息,包含其下SalesLine的内容。这么复杂的订单内容不可能手工取编写,所以一般是先用read操作读取订单的内容到XML,然后更改这个XML的订单内容、更改头中的服务操作、并加上EntityKeyList节,就得到了一个更新文档的消息。所以更新数据是要先读再更新,而且必须这样做,因为涉及到并发操作的问题,一条记录可能在你递交消息前已经被其他途径更改,如果不加控制,你的数据就会改写其他人的更改,这是需要避免的。AIF检测并发冲突有两种方法,一是文档哈希值(消息中的_DocumentHash标记),二是RecId和RecVersion。
通过AIF read操作读取文档时AIF会使用文档包含的所有数据库记录的RecId、RecVersion计算得到一个哈希值包含在<_DocumentHash>节点,在把更新数据发回到AIF时,系统再次计算当前数据库中所有记录的RecId、RecVersion哈希值,如果两者不一致就知道数据库中的记录已经被更改过,AIF返回错误提示。使用这种方法不需要在XML文档中包含所有记录的RecId和RecVersion,但是一旦出现并发冲突AIF无法判断出具体是哪条记录。
更直接的方法是在消息中加入每条记录的RecId和RecVersion,如果消息中既不包含文档哈希值也不包含所有记录的RecId、RecVersion,更新操作会失败,相反,如果两者都有,它们会同时被检查。
- Partial update - 部分更新则只更新出现在提交消息中的字段,对于未出现在消息中的字段不予更改,但是对于那些依赖于其他子段但又未出现在提交消息中的字段会依照默认规则设置为默认值,比如字段FullName是FirstName和LastName组合生成,如果FirstName或者LastName被更新而FullName未出现在提交消息中,FullName会被更新为默认值。总的来说有这几种情况:
- 字段未出现在消息中 —— 表字段保持不变
- 消息中指定为XML NULL值(<Field>xsi:nil</Field>) -- 表字段保持不变
- 消息中指定某个值(<Field>123</Field>)、或者空(<Field></Field>)、或者X++的NULL空值 -- 表字段被更新为指定值
在一个消息中可以同时更新多个文档记录,即在EntityKeyList节可以包含多个EntityKey,与此对应,消息中需要包含同样数目的文档记录数据。在每一个文档记录数据包括子文档记录上单独指定操作Action时启用部分更新,比如:
-
- <SalesTable class="entity" action="update"> —— 更新销售订单
- <SalesLine class="entity" action="update"> —— 更新销售订单行
- <SalesLine class="entity" action="create"> —— 创建销售订单行
- <SalesLine class="entity" action="delete"> —— 删除销售订单行
一个部分更新操作XML消息的样例:
<?xml version="1.0" encoding="utf-8" ?> <Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/ 01/documents/Message"> <Header> <Action>http://www.microsoft.com/dynamics/services/2008/01/SalesOrderService/update</Action> </Header> <Body> <MessageParts xmlns = "http://schemas.microsoft.com/dynamics/2008/01/documents/Message"> <EntityKeyList xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList"> <EntityKey xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey"> <KeyData> <KeyField> <Field>CustAccount</Field> <Value>10002</Value> </KeyField> </KeyData> </EntityKey> </EntityKeyList> <SalesOrder xmlns="http://schemas.microsoft.com/dynamics/ 2008/01/documents/SalesOrder"> <SalesTable class="entity" action="update"> <CustAccount>10002</CustAccount> <_DocumentHash>d2394857bffgg23924718kxk2908zj3s</_DocumentHash> <SalesLine class="entity" action="update"> <ItemId>4710003</ ItemId > … 删除部分数据 … <SalesQty>77</ SalesQty > <SalesUnit>Pcs</ SalesUnit > </SalesLine> <SalesLine class="entity" action="create"> <ItemId>4710005</ ItemId > … 删除部分数据 … </SalesLine> <SalesLine class="entity" action="delete"> <ItemId>4710001</ ItemId > … 删除部分数据 … </SalesLine> </SalesTable> </SalesOrder> </MessageParts> </Body> </Envelope>
同样部分更新的XML文档中必须包含文档哈希值或者RecId、RecVersion来检查并发操作。