【背景说明】
K/3 Cloud封装的单据保存、删除、审核、反审核等操作,会自动启动一个事务
操作的标准处理过程如下:
1. 进行操作校验;
2. 触发操作插件 BeforeExecuteOperationTransaction 事件;
3. 启动事务保护(如果外围已经启动了事务,则沿用外围事务)
4. 触发操作插件 BeginOperationTransaction 事件;
5. 执行保存、删除、审核、反审核等操作,对数据库的更新处理;
6. 触发操作插件 EndOperationTransaction 事件;
7. 提交事务;
8. 触发操作插件 AfterExecuteOperationTransaction 事件。
如上,操作插件的 BeginOperationTransaction 、EndOperationTransaction 两个事件,是在事务中的。
如果在此事件中,调用了其他单据的保存、提交等操作,称为嵌套操作。
【嵌套操作可能引发的问题】
嵌套调用的操作,会直接沿用外围操作所启动的事务。如果嵌套操作成功,代码会顺利的回到外围操作代码,随后提交整个事务,完成整个过程,万事大吉。
如果嵌套操作不成功,嵌套操作会自动回滚事务。
注意,此时因为嵌套操作,实际上使用的是外围操作的事务,回滚事务,其实回滚的是外围操作的事务。
回滚事务之后,与数据库的链接自动关闭,此时,要力图避免任何与数据库的交互。
如果此时尝试到数据库读取、存储数据,
即会引发下面这个经典错误:
此操作对该事务的状态无效
The operation is not valid for the state of the transaction.
错误反馈贴:
流程审核的时候,出现 此操作对该事务的状态无效销售出库单审核报错,麻烦谁遇见这个问题给看一下?
流程审核的时候,出现 此操作对该事务的状态无效 (kingdee.com)
典型错误代码:
//保存操作完毕,事务结束之前,进行自动提交、审核 public override void EndOperationTransaction(EndOperationTransactionArgs e) { // 取到需要自动提交、审核的单据内码 object[] pkArray = (from p in e.DataEntitys select p[0]).ToArray(); // 设置提交参数 OperateOption submitOption = OperateOption.Create(); submitOption.SetIgnoreWarning(this.Option.GetIgnoreWarning()); submitOption.SetInteractionFlag(this.Option.GetInteractionFlag()); submitOption.SetIgnoreInteractionFlag(this.Option.GetIgnoreInteractionFlag()); // 创建提交服务 ISubmitService submitService = ServiceHelper.GetService(); IOperationResult submitResult = submitService.Submit( this.Context, this.BusinessInfo, pkArray, "Submit", submitOption); // 未判断提交是否成功,随后直接调用审核操作 // 构建操作可选参数对象 OperateOption auditOption = OperateOption.Create(); auditOption.SetIgnoreWarning(this.Option.GetIgnoreWarning()); auditOption.SetInteractionFlag(this.Option.GetInteractionFlag()); auditOption.SetIgnoreInteractionFlag(this.Option.GetIgnoreInteractionFlag()); // 构建单据主键参数 List> pkEntityIds = new List>(); foreach (var pkValue in pkArray) { pkEntityIds.Add(new KeyValuePair(pkValue, "")); } List paras = new List(); paras.Add("1"); paras.Add(""); // 调用审核操作 ISetStatusService setStatusService = ServiceHelper.GetService(); // 如下调用方式,需显示交互信息 IOperationResult auditResult = setStatusService.SetBillStatus(this.Context,this.BusinessInfo,pkEntityIds,paras,"Audit",auditOption); // 不判断审核是否成功,直接结束,使代码顺利往后执行 }
错误代码说明:
上述代码中,在操作插件的事务内事件EndOperationTransaction中,连续调用了单据的提交、审核操作。
但是并未判断调用的提交、审核操作是否成功。
如果提交操作失败,随后调用审核操作,即会因为外围事务已经回滚,与数据库的链接已经关闭,而引发中断。
此时,正确的做法判断提交操作状态,如果提交失败,即刻把失败原因通过抛出错误的方式给出,并结束流程。对审核操作的处理也一样。
正确处理代码:知识共享 - 保存操作,同时进行自动提交、审核 (kingdee.com)
推荐阅读