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

Acumatica 19R1中BQL生成SQL参数不匹配导致查询明细记录时出现运行时错误

解决Acumatica 19R1中PXDBScalar参数绑定错误的问题

问题背景

你在Acumatica 19R1里遇到了一个棘手的运行时错误:当尝试调取未用PXSelector的现有记录时,生成的SQL语句因为PXSelector和PXDBScalar的逻辑混合,加上DAC继承操作,出现了参数不匹配的问题。具体来说,子查询里错误地把XPMPaymentHdrAssocDoc.AssocDocID(字符串类型的单据号)绑定到了整数类型的@P1(客户ID),导致SQL抛出nvarchar转int失败的错误。而PXUnboundDefault能正常工作,但你需要在PXSelector的PXRestrictor里使用这个计算字段,所以PXUnboundDefault的方案没法直接满足需求。

问题根源

这个问题是Acumatica 19R1框架的一个已知bug:当PXDBScalar引用继承DAC的Current字段,且主查询中存在多个不同类型的Current引用时,框架的SQL参数绑定逻辑会混乱,把字符串类型的字段错误绑定到整数参数上。PXUnboundDefault之所以没问题,是因为它的计算是在内存层面处理的,不走SQL参数映射的流程。


解决方案

下面给你三个可行的方案,你可以根据项目情况选择:

方案1:用PXUnboundDefault+缓存事件适配Restrictor需求

既然PXUnboundDefault能正确计算值,我们可以通过缓存事件确保计算值在查询时被正确加载,这样就能在PXRestrictor里正常使用了:

  1. 修改XPMARRegister DAC:把PXDBScalar替换回PXUnboundDefault,还可以加一个派生的计算字段方便Restrictor调用:
[System.SerializableAttribute()] 
[PXHidden]
public class XPMARRegister : ARRegister {
    // 保留原有继承字段...

    public abstract class xPMPaymentHdrAssocDocUnrelasedPaymentAmount : PX.Data.IBqlField { }
    
    // 用PXUnboundDefault替代PXDBScalar,确保参数绑定正确
    [PXUnboundDefault(typeof(Select5<
        XPMPaymentHdrAssocDoc,
        InnerJoin<XPMPaymentHdr, On<XPMPaymentHdr.paymentID, Equal<XPMPaymentHdrAssocDoc.paymentID>>>,
        Where<XPMPaymentHdrAssocDoc.assocDocType, Equal<Current<XPMARRegister.docType>>,
            And<XPMPaymentHdrAssocDoc.assocDocID, Equal<Current<XPMARRegister.refNbr>>,
            And<Where<XPMPaymentHdr.status, Equal<PaymentStatusList.applied>,
                Or<XPMPaymentHdr.status, Equal<PaymentStatusList.eligibleforSubmission>,
                Or<XPMPaymentHdr.status, Equal<PaymentStatusList.open>,
                Or<XPMPaymentHdr.status, Equal<PaymentStatusList.approved>>>>>>>>),
        Aggregate<Sum<XPMPaymentHdrAssocDoc.amount>>>),
    SourceField = typeof(XPMPaymentHdrAssocDoc.amount), 
    PersistingCheck = PXPersistingCheck.Nothing]
    [PXDecimal(4)]
    public virtual Decimal? XPMPaymentHdrAssocDocUnrelasedPaymentAmount { get; set; }

    // 添加派生字段,用于Restrictor判断
    public abstract class docBalLessUnreleased : PX.Data.IBqlField { }
    [PXDecimal(4)]
    [PXUnboundDefault(typeof(Sub<XPMARRegister.docBal, XPMARRegister.xPMPaymentHdrAssocDocUnrelasedPaymentAmount>))]
    public virtual Decimal? DocBalLessUnreleased { get; set; }
}
  1. 在Graph中添加缓存事件:确保XPMARRegister的计算字段在查询时被正确计算:
public class XPARInvoicePayment : PXGraph<XPARInvoicePayment, XPMPayAppHdr> {
    // 保留原有视图...

    public XPARInvoicePayment()
    {
        // 注册RowSelected事件,触发计算字段更新
        this.Caches[typeof(XPMARRegister)].RowSelected += XPMARRegister_RowSelected;
    }

    private void XPMARRegister_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
    {
        var row = e.Row as XPMARRegister;
        if (row == null) return;
        
        // 手动触发字段计算,确保派生字段值正确
        sender.RaiseFieldUpdated<XPMARRegister.docBal>(row, row.DocBal);
    }
}
  1. 更新Restrictor:现在可以直接用派生字段做判断了:
[PXRestrictor(typeof(Where<XPMARRegister.docBalLessUnreleased, Greater<decimal0>>), Messages.DocumentNotOpen)]

方案2:修改PXDBScalar的查询逻辑,强制参数绑定

如果必须用PXDBScalar,可以把Current替换成Required,强制框架为每个字段创建独立的参数,避免混淆:

[PXDBScalar(typeof(Search5<
    XPMPaymentHdrAssocDoc.amount,
    InnerJoin<XPMPaymentHdr, On<XPMPaymentHdr.paymentID, Equal<XPMPaymentHdrAssocDoc.paymentID>>>,
    Where<XPMPaymentHdrAssocDoc.assocDocType, Equal<Required<XPMARRegister.docType>>,
        And<XPMPaymentHdrAssocDoc.assocDocID, Equal<Required<XPMARRegister.refNbr>>,
        And<Where<XPMPaymentHdr.status, Equal<PaymentStatusList.applied>,
            Or<XPMPaymentHdr.status, Equal<PaymentStatusList.eligibleforSubmission>,
            Or<XPMPaymentHdr.status, Equal<PaymentStatusList.open>,
            Or<XPMPaymentHdr.status, Equal<PaymentStatusList.approved>>>>>>>>),
    Aggregate<Sum<XPMPaymentHdrAssocDoc.amount>>>))]
[PXDecimal(4)]
public virtual Decimal? XPMPaymentHdrAssocDocUnrelasedPaymentAmount { get; set; }

Required会告诉框架为对应的字段生成独立的SQL参数,不会和其他参数混淆。

方案3:升级Acumatica版本(最彻底的解决办法)

这个参数绑定的bug在Acumatica 20R1及以后的版本里已经被官方修复了。如果你的项目允许升级,直接升级到新版本就能彻底解决这个问题,不用改代码。


验证方法

  1. 应用方案后重新发布站点。
  2. 打开XPARInvoicePayment页面,尝试选择关联单据,看是否还会报错。
  3. 用SQL Profiler监控生成的SQL,确认子查询里的AssocDocID已经正确绑定到单据编号参数(@P3),而不是客户ID(@P1)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 11:27:55