You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:出现‘Another process is updating "table", Records will be lost’报错

解决Acumatica中“Another process is updating 'table', Records will be lost”并发更新报错

这个报错在Acumatica开发里太常见了,本质是同一数据库记录被两个独立的操作上下文(主线程和PXLongOperation启动的后台线程)同时修改,触发了缓存的版本冲突检查——Acumatica这么做是为了防止你的修改意外覆盖掉其他操作的变更。结合你描述的场景:上传Excel后在DetailsForm的RowInserted事件更新字段,点击发布按钮又通过PXLongOperation执行二次更新,我给你几个针对性的解决方案:

核心原因分析

PXLongOperation.StartOperation会启动一个全新的后台线程,这个线程会创建独立的PXGraph实例和缓存上下文。如果主线程(比如你在PreLoadData函数里的操作)已经修改了缓存里的记录但还没同步到数据库,后台线程再去更新同一记录时,就会因为缓存版本不匹配触发这个错误——系统会误认为有另一个外部进程在修改这条记录,直接更新会导致数据丢失。

解决方案

1. 让后台线程基于最新数据库记录更新

不要让后台线程直接复用主线程缓存里的记录,而是在后台线程中重新从数据库获取最新版本的记录,再执行更新。这样能确保后台操作基于当前数据库的最新状态,彻底避免版本冲突:

// 主线程启动长操作时,只传递记录ID即可
PXLongOperation.StartOperation(this, delegate ()
{
    using (var transactionScope = new PXTransactionScope())
    {
        // 创建独立的Graph实例,完全隔离主线程缓存
        var targetGraph = PXGraph.CreateInstance<YourDetailsFormGraph>();
        // 用记录ID查询数据库里的最新版本
        ISLoanRegister targetDoc = targetGraph.Document.Search<ISLoanRegister.loanRegisterID>(doc.loanRegisterID);
        
        if (targetDoc != null)
        {
            // 在这里执行发布后的更新逻辑
            targetDoc.TargetField = "UpdatedValue";
            targetGraph.Document.Update(targetDoc);
            targetGraph.Actions.PressSave();
        }
        
        transactionScope.Complete();
    }
});

2. 主线程修改后先同步到数据库

如果主线程RowInserted事件的更新必须在长操作前完成,那在启动PXLongOperation之前,先把主线程缓存的修改保存到数据库,让后台线程能拿到最新的记录:

private void PublishButton_Click(PXCache cache, PXRowSelectedEventArgs e)
{
    ISLoanRegister doc = this.Document.Current;
    // 先保存主线程的修改(比如RowInserted里的字段更新)
    if (this.Document.Cache.GetStatus(doc) != PXEntryStatus.Notchanged)
    {
        this.Document.Save.Press();
    }
    
    // 再启动长操作执行后续更新
    PXLongOperation.StartOperation(this, delegate ()
    {
        // 后台更新逻辑
    });
}

3. 合并重复的更新逻辑

检查RowInserted事件的更新和发布按钮的更新是否有重复部分,如果其中一个更新可以整合到另一个操作里,就去掉重复步骤。比如把RowInserted里的字段更新逻辑移到发布的长操作中,统一在后台处理,从根源避免并发冲突。

4. 数据库层面锁定记录(可选)

如果你的场景需要严格保证记录不被其他操作干扰,可以在后台线程中用PXSelectForUpdate查询记录,这样会在数据库层面锁定这条记录,直到后台操作完成:

ISLoanRegister targetDoc = PXSelectForUpdate<ISLoanRegister, Where<ISLoanRegister.loanRegisterID, Equal<Required<ISLoanRegister.loanRegisterID>>>>
    .Select(targetGraph, doc.loanRegisterID);

额外提醒

永远记住:PXLongOperation的后台线程和主线程是完全独立的上下文,不要共享缓存对象。所有后台操作需要的数据,要么通过参数传递基本类型(比如ID),要么在后台线程中重新查询获取,不要直接传递主线程的缓存实体。

内容的提问来源于stack exchange,提问作者Eds

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:03:10