Farseer

导航

关于更改当前公司(三)--一个奇怪的问题

在写代码的时候遇到一个非常奇怪的问题,感觉是AX类Application的setDefaultCompany和ChangeCompany方法冲突了。我要实现的功能很简单,从外部数据中读取数据,然后写到相关表中,因为外部数据表中包含多个公司的数据所以我要用到ChangeCompany,根据情况把数据插入到不同的公司中,如下所示:
Code
其中调用的方法insert_AXSalesLine如下所示:
Code
由于外部的数据量比较大,所以while循环运行的时间比较长,不知道为什么这段程序偶尔会报错说,未指定销售订单号,并且提示公司切换到**公司,**公司正是当前打开的Client指定公司,然后退出。经过跟踪发现,在调用CCADO*相关类的方法时会触发类Application的setDefaultCompany方法,该方法把公司切换到了Client所指定的公司001,而实际上我的语句运行的语境应该在ChangeCompany方法指定的公司下,它帮我切换到了Client当前指定的公司,当然就会找不到相应的销售订单了,关键是干么要帮我调用Application的setDefaultCompany方法,这明显是不合适的,它这样一调用,把我的当前公司又给切换回去了,语境变了,后面的运行都是错的了。查MSDN也没找到一个具体在什么情况下会调用Application的setDefaultCompany方法的说明,只能自己一一排除了。经过反复测试,按如下说明可复现上述问题:
1.新建一个类,随便取什么名字,比如叫ChangeCompanyProblem之类的,默认情况下该类的RunOn属性为Called from
2.重载该类的new方法,不需要修改任何代码。
3.新建一个main方法,代码如下:


Code

这里的sleep方法,只是模拟正常情况下的一些耗时的计算,假设从select firstonly salesTable运行到problem = new ChangeCompanyProblem()需要10S,这个在一般的场景中应该是比较常见的。

4.新建一个MenuItem让其指向该类,默认情况下该MenuItem的RunOn属性为Client

5.在MainMenu中新建菜单项让其指向该MenuItem
6.在AX的标准菜单(实际上如果不通过AX的标准菜单项而是在AOT里直接打开菜单或者菜单项是不会出问题的)中打开该菜单项,在运行的时候点击客户端界面,随便点哪里,比如其他的菜单项之类的。
7.如果当前公司是"002",应该会出现如下提示:

从上面的步骤可以看出,应该是在实例化类ChangeCompanyProblem的时候把当前公司从001切换到了002,在类ChangeCompanyProblem的new方法和类Application的setDefaultCompany里加断点跟踪也可以得出这样的结论。
将类ChangeCompanyProblem的Runon属性变成Server或者不重载类的new方法,再实例化的时候也就不会切换当前公司了,于是得出如下结论:

如果通过AX的标准菜单项调用一个类实现某个功能,在切换了公司的语境下,在该类的某个方法里要实例化其他类,而被实例化的类的new方法被重载了且用户在实例化该类之前在AX界面上有其他操作(比如随便点击界面的某个地方),如果该类被实例化时发生在客户端,将会触发类Application的setDefaultCompany,导致当前公司切换至当前Client所指定的公司,这样该类被实例化后,所有的代码执行的语境将会被更改至Client的当前公司而不是ChangeCompany所指定的公司,会产生与预期不同的结果。貌似很绕口的说。。。
所以需要注意以下两点:
1.如果要在ChangeCompany包括的语句中实例化类,一定要让这些类运行在服务器端;
2.避免在ChangeCompany包括的语句中调用info,print之类的向客户端打印信息的方法,因为这也会导致application的stDefaultCompany的调用。
由于以上只是出于自己的简单测试,没有见过相应的权威的解释,没办法从原理上得到合理的解释,只是通过有限的测试得到的结果,不能保证正确性,还望高手指点。

测试版本 AX2009 SP1(RU3)

posted on 2009-11-16 13:18  佛西亚  阅读(830)  评论(2编辑  收藏  举报