update_recordset降级的问题

<<Microsoft Inside Dynamics AX4.0>>的第十七章中在介绍批操作符update_recordset时提到在几种情况下可能会导致update_recordset降级,变成逐条更新,降级后的update_recordset会按照while select语句的处理方式完成更新,并举了如下例子:

static void UpdateSizes(Args _args)
{
    InventSize inventSize;
    ;
    ttsbegin;
        update_recordset inventSize
        setting description 
= 'This size is for item PB-Metal Shade'
        where inventSize.ItemId 
== 'PB-Metal Shade';
    ttscommit;

}
由于表InventSize没有满足使update_recordset降级的任何一个条件,所以上述语句在执行的时候将执行批处理操作,执行的SQL语句如下:
版本: Microsoft Dynamics 4.0 (内部版本号 2163)
数据库: Microsoft SQL Server
SQL 语句: UPDATE INVENTSIZE SET DESCRIPTION
=?,RECVERSION=? WHERE ((DATAAREAID=?) AND (ITEMID=?)) [ID=386, 已重用=否]
这没有任何问题,inventsize中相应产品的描述信息被更改。
我们让该表满足使update_recordset降级的一个条件,比如重载一下update方法,然后更改一下UpdateSizes方法中的description的值(因为如果本次更新的值跟原表中相应记录的值一样,while select只执行select语句,并不会执行更新语句)
static void UpdateSizes(Args _args)
{
    InventSize inventSize;
    ;
    ttsbegin;
        update_recordset inventSize
        setting description 
= 'update_recordset test'
        where inventSize.ItemId 
== 'PB-Metal Shade';
    ttscommit;

}
理论上应该降级成while select 语句完成更新,可是实际上并没有执行更新操作,查看执行的SQL语句,只有一条select语句
版本: Microsoft Dynamics 4.0 (内部版本号 2163)
数据库: Microsoft SQL Server
SQL 语句: SELECT A.INVENTSIZEID,A.ITEMID,A.NAME,A.RECVERSION,A.RECID,A.DESCRIPTION FROM INVENTSIZE A WITH( INDEX(I_1616ITEMSIZEIDX)) WHERE ((DATAAREAID
=?) AND (ITEMID=?)) [ID=360, 已重用=是]
这个蛮让人费解,把上述语句改成while select语句:
static void UpdateSizes(Args _args)
{
    InventSize inventSize;
    ;
    ttsbegin;
        
while select forupdate inventSize
        where inventSize.ItemId 
== 'PB-Metal Shade'
        
{
            inventSize.Description 
= 'update_recordset test';
            inventSize.update();
        }

    ttscommit;

}
执行了两条SQL语句:
数据库: Microsoft SQL Server
SQL 语句: SELECT A.INVENTSIZEID,A.ITEMID,A.NAME,A.RECVERSION,A.RECID,A.DESCRIPTION FROM INVENTSIZE A WITH( INDEX(I_1616ITEMSIZEIDX)) WHERE ((DATAAREAID
=?) AND (ITEMID=?)) [ID=10, 已重用=否]

版本: Microsoft Dynamics 4.0 (内部版本号 2163)
数据库: Microsoft SQL Server
SQL 语句: 
UPDATE INVENTSIZE SET DESCRIPTION=?,RECVERSION=WHERE ((((DATAAREAID=?) AND (ITEMID=?)) AND (INVENTSIZEID=?)) AND (RECVERSION=?)) [ID=11, 已重用=否]
可以正常更新.
这应该说明问题出在update_recordset没有成功降级成while select 语句。
尝试更新了一下其他字段:
static void UpdateSizes(Args _args)
{
    InventSize inventSize;
    ;
    ttsbegin;
        update_recordset inventSize
        setting name 
= 'update_recordset test'
        where inventSize.ItemId 
== 'PB-Metal Shade';
    ttscommit;

}
上面的例子更新了inventSize的name字段,该方法执行了两条SQL语句,一条查询一条更新。
说明顺利完成了降级为while select的操作,正常更新了相应记录。
综上所述,造成updae_recordset不能正常降级的原因应该是字段类型的问题,对照了一下description和name两个字段,它们的基类型都是string,只不过name是stringsize属性为60的string,而description是stringsize属性为memo的string类型,两者在SQL Server2005中对应的类型分别为nvarchar(60)和nText。
尝试把字段description对应EDT的stringsize改成某个长度而不是memo,update_recordset就可以顺利降级了。
测试了其他的类型int,real,date,time,enum,container,其中int,real,date,time,enum没有问题,在测试container的时候郁闷的事情又发生了,给inventsize添加一个container类型的字段containertest,重载inventsize的update方法,执行如下方法:
static void UpdateSizes(Args _args)
{
    InventSize inventSize;
    ;
    ttsbegin;
        update_recordset inventSize
        setting containertest 
= [2,4]
        where inventSize.ItemId 
== 'PB-Metal Shade';
    ttscommit;

}
执行后AOS当掉了,查看事件查看器,在系统日志中得到如下信息:
事件类型:    错误
事件来源:    Service Control Manager
事件种类:    无
事件 ID:    
7034
描述:
服务 Dynamics Server$
01-Dynamics 意外停止。这发生了 3 次。

有关更多信息,请参阅在 http:
//go.microsoft.com/fwlink/events.asp 的帮助和支持中心。

在控制命令行里用sc query aos$01查看WIN32_EXIT_CODE ,得到如下结果:
SERVICE_NAME: aos$01
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 1  STOPPED
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN))

        WIN32_EXIT_CODE    : 1067  (0x42b)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
运行net helpmsg 1067查看具体的帮助信息得到如下信息:
进程意外终止
这个信息没啥帮助。
查看应用程序日志:

事件类型:    错误
事件来源:    Application Error
事件种类:    (
100)
事件 ID:    
1000
计算机:    ADSERVER
描述:
错误应用程序 Ax32Serv.exe,版本 
4.0.2163.0,错误模块 Ax32Serv.exe,版本 4.0.2163.0,错误地址 0x00322810

有关更多信息,请参阅在 http:
//go.microsoft.com/fwlink/events.asp 的帮助和支持中心。
数据:
000041 70 70 6c 69 63 61 74   Applicat
000869 6f 6e 20 46 61 69 6c   ion Fail
001075 72 65 20 20 41 78 33   ure  Ax3
001832 53 65 72 76 2e 65 78   2Serv.ex
002065 20 34 2e 30 2e 32 31   e 4.0.21
002836 33 2e 30 20 69 6e 20   63.0 in 
003041 78 33 32 53 65 72 76   Ax32Serv
0038: 2e 65 78 65 20 34 2e 30   .exe 4.0
0040: 2e 32 31 36 33 2e 30 20   .2163.0 
004861 74 20 6f 66 66 73 65   at offse
005074 20 30 30 33 32 32 38   t 003228
005831 30                     10      

通过系统和应用程序的日志还真整不明白到底是什么原因造成的服务意外终止。

综上所述,AX在处理update_recordset降级的时候有两个问题:
1.如果字段类型是string且stringsize属性为memo,则只会执行select动作,不会执行更新动作;
2.如果字段类型是container类型,则会引发AOS服务的意外终止。

换了几个环境测试都存在上述问题,按理说原书的作者应该测试过书中所举的例子,不知道是不是还需要配置什么信息,如果配置都正确的话应该就是AX平台的bug或者局限性了。

原文地址:https://www.cnblogs.com/Farseer1215/p/738761.html