调用CopyOrder遇SOOrder记录冲突错误,求进程检测命令及解决办法
问题场景
调用PX.Objects.SO.SOOrderEntry.CopyOrder(PXAdapter adapter)时触发错误:
Error: Another process has added the 'SOOrder' record. Please try again
询问是否有方式检测当前是否存在其他正在执行的处理,并附上了自定义的订单头计算代码及触发事件:
自定义订单头计算方法(calcultotal)
SOOrder cmd=CurrentSOOrder.Select(); PXTrace.WriteInformation("CMD"+cmd.OrderNbr); cmd.GetExtension<SOOrderExt>().Usrtotalcout=totalcout; cmd.GetExtension<SOOrderExt>().Usrpourcentcout=0; if ((totalnet!=0) && (totalcout!=0)) { cmd.GetExtension<SOOrderExt>().Usrpourcentcout=(totalnet-totalcout)/(totalnet)*100; } try { Base.Caches[typeof(PX.Objects.SO.SOOrder)].MarkUpdated(cmd); Base.Document.View.RequestRefresh(); } catch(Exception e) { PXTrace.WriteInformation(e.StackTrace); } return true; }
SOOrder_RowUpdated触发事件
protected void SOOrder_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e) { var row = (SOOrder)e.Row; if (row==null) return; row.OverrideTaxZone=true; calcultotal(false); // calcul l'entête pour les webservices }
问题分析与解决
一、检测并发/正在执行的处理
Acumatica没有直接的命令式检测工具,但可以通过以下代码片段排查:
- 检查是否有长时间运行的操作:
Guid? runningOpId = PXLongOperation.GetRunningOperationID(Base); if (runningOpId != null) { PXTrace.WriteInformation("当前存在运行中操作,ID:" + runningOpId); } - 查看缓存内的修改记录,判断是否有未提交的冲突操作:
// CopyOrder执行前后分别输出 PXTrace.WriteInformation("CopyOrder前SOOrder缓存修改数:" + Base.Caches[typeof(SOOrder)].GetModified().Count()); // 执行CopyOrder逻辑 PXTrace.WriteInformation("CopyOrder后SOOrder缓存修改数:" + Base.Caches[typeof(SOOrder)].GetModified().Count());
二、修复CopyOrder冲突问题
错误根源是CopyOrder过程中,RowUpdated事件触发的自定义修改与原生复制逻辑产生缓存冲突。你的代码直接从CurrentSOOrder查询记录并标记更新,在复制订单时,缓存内同时存在原订单和新订单,导致状态混乱。
代码优化方案
- 修改
calcultotal方法,直接使用事件传入的订单行,避免查询CurrentSOOrder:private bool calcultotal(SOOrder targetOrder, bool someFlag) { if (targetOrder == null) return false; var orderExt = targetOrder.GetExtension<SOOrderExt>(); orderExt.Usrtotalcout = totalcout; orderExt.Usrpourcentcout = 0; if ((totalnet != 0) && (totalcout != 0)) { orderExt.Usrpourcentcout = (totalnet - totalcout) / totalnet * 100; } try { Base.Caches[typeof(SOOrder)].MarkUpdated(targetOrder); } catch(Exception e) { PXTrace.WriteInformation(e.StackTrace); } return true; } - 调整RowUpdated事件,直接传入当前行:
protected void SOOrder_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e) { var row = (SOOrder)e.Row; if (row == null) return; row.OverrideTaxZone = true; calcultotal(row, false); } - 重写CopyOrder操作,临时禁用自定义RowUpdated事件,避免干扰复制逻辑:
public PXAction<SOOrder> CustomCopyOrder; [PXButton(CommitChanges = true)] [PXUIField(DisplayName = "Copy Order")] protected IEnumerable customCopyOrder(PXAdapter adapter) { // 临时移除自定义RowUpdated事件 Base.RowUpdated.RemoveHandler<SOOrder>(SOOrder_RowUpdated); try { // 执行原生CopyOrder逻辑 return Base.CopyOrder.Press(adapter); } finally { // 恢复事件处理 Base.RowUpdated.AddHandler<SOOrder>(SOOrder_RowUpdated); } }
额外优化建议
- 优先使用
RowPersisting事件替代RowUpdated,该事件在记录保存前触发,避免缓存冲突 - 修改扩展字段时,使用
cache.SetValueExt触发Acumatica原生验证逻辑:cache.SetValueExt<SOOrderExt.usrTotalcout>(targetOrder, totalcout);
内容的提问来源于stack exchange,提问作者Xavier LARTEM
相关产品推荐
相关产品推荐

