Acumatica投影DAC选中行数据空白,仅返回键值问题排查求助
问题描述
这是此前《Projection brings in duplicate data on DAC》问题的跟进,因属于同一用例下的独立问题故单独提出。
我定义了一个合并FSAppointmentDet与FSSODet的Projection DAC,并基于FSAppointmentDet的主键设置了SrvOrdType、LineNbr、RefNbr作为键值,以确保数据正确显示。流程页面加载时能正常展示记录,但选中任意行后,该行除LineNbr列外其余数据均变为空白。调试时发现,执行处理例程时,DAC实例中仅键值字段有值。请问我遗漏了什么配置?
DAC代码
[PXProjection(typeof(Select2<FSAppointmentDet, InnerJoin<FSSODet, On<FSSODet.refNbr, Equal<FSAppointmentDet.origSrvOrdNbr>, And<FSSODet.lineNbr, Equal<FSAppointmentDet.origLineNbr>>>>, Where<FSSODet.unitPrice, NotEqual<FSAppointmentDet.unitPrice>>>), Persistent = true)] [PXCacheName("FixPriceProjection")] public class PriceProjDAC : IBqlTable { #region Selected public abstract class selected : IBqlField { } protected bool? _Selected = false; [PXBool] [PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)] [PXUIField(DisplayName = "Selected")] public virtual bool? Selected { get { return _Selected; } set { _Selected = value; } } #endregion #region From the FSAppointmentDet DAC #region SrvOrdType public abstract class srvOrdType : PX.Data.BQL.BqlString.Field<srvOrdType> { } [PXDBString(IsKey = true, BqlField = typeof(FSAppointmentDet.srvOrdType))] public virtual string SrvOrdType { get; set; } #endregion #region LineNbr public abstract class lineNbr : PX.Data.BQL.BqlInt.Field<lineNbr> { } [PXDBInt(IsKey = true, BqlField = typeof(FSAppointmentDet.lineNbr))] public virtual int? LineNbr { get; set; } #endregion #region RefNbr public abstract class refNbr : PX.Data.BQL.BqlString.Field<refNbr> { } [PXDBString(IsKey = true, BqlField = typeof(FSAppointmentDet.refNbr))] public virtual string RefNbr { get; set; } #endregion #region OrigSrvOrdNbr public abstract class origSrvOrdNbr : PX.Data.BQL.BqlString.Field<origSrvOrdNbr> { } [PXDBString(BqlField = typeof(FSAppointmentDet.origSrvOrdNbr))] public virtual string OrigSrvOrdNbr { get; set; } #endregion #region FDUnitPrice [PXDBDecimal(4, BqlField = typeof(FSAppointmentDet.unitPrice))] [PXUIField(DisplayName = "Appt Price")] public virtual decimal? FDUnitPrice { get; set; } public abstract class fDUnitPrice : PX.Data.BQL.BqlDecimal.Field<fDUnitPrice> { } #endregion #endregion #region From the FSSODet DAC #region FSRefNbr [PXDBString(20, IsUnicode = true, BqlField = typeof(FSSODet.refNbr))] public virtual string FSRefNbr { get; set; } public abstract class fSRefNbr : PX.Data.BQL.BqlString.Field<fSRefNbr> { } #endregion #region FSLineNbr [PXDBInt(BqlField = typeof(FSSODet.lineNbr))] public virtual int? FSLineNbr { get; set; } public abstract class fSLineNbr : PX.Data.BQL.BqlInt.Field<fSLineNbr> { } #endregion #region FSUnitPrice [PXDBDecimal(4, BqlField = typeof(FSSODet.unitPrice))] [PXUIField(DisplayName = "SO Price")] public virtual decimal? FSUnitPrice { get; set; } public abstract class fSUnitPrice : PX.Data.BQL.BqlDecimal.Field<fSUnitPrice> { } #endregion #region TranDesc [PXDBString(255, IsUnicode = true, BqlField = typeof(FSSODet.tranDesc))] public virtual string TranDesc { get; set; } public abstract class tranDesc : PX.Data.BQL.BqlString.Field<tranDesc> { } #endregion #endregion }
流程页面Graph代码
public class PSFixPrice : PXGraph<PSFixPrice> { // Define the processing view which will select all // correct records baswd on the definition in the projection public PXProcessing<PriceProjDAC> Processing; public PSFixPrice() { var tst = new PriceProjDAC(); int i = 0; // Acuminator disable once PX1008 LongOperationDelegateSynchronousExecution [Justification] Processing.SetProcessDelegate( delegate (List<PriceProjDAC> list) { DoLogic(list, Processing.Cache); }); } static public void DoLogic(IList records, PXCache onCache) { var onGraph = onCache.Graph; PXLongOperation.StartOperation(onGraph, delegate () { var cacheName = onCache.GetName(); using (PXTransactionScope FSSODETScope = new PXTransactionScope()) { foreach (var item in records ) { try { PriceProjDAC projDAC = item as PriceProjDAC; if (projDAC != null) { ProcessItem(projDAC, onCache); } } catch { } } // Save all changes after processing all items // onGraph.Actions.PressSave(); FSSODETScope.Complete(); } // End PXTransactionScope }); // PXLongOperation end brace } // doLogic end brace // Define the processing logic for each item static private void ProcessItem(PriceProjDAC item, PXCache onCache) { if (item.Selected == true) { // Update the FSSODet UnitPrice with FSAppointmentDet UnitPrice // item.FSUnitPrice = item.FDUnitPrice; // Update the record in the cache // onCache.Update(item); } } }
ASPX代码
<%@ Page Language="C#" MasterPageFile="~/MasterPages/ListView.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="PS305020.aspx.cs" Inherits="Page_PS305020" Title="SO Price Fix Page" %> <%@ MasterType VirtualPath="~/MasterPages/ListView.master" %> <asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server"> <px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" TypeName="ASGFix.PSFixPrice" PrimaryView="Processing" > <CallbackCommands> </CallbackCommands> </px:PXDataSource> </asp:Content> <asp:Content ID="cont2" ContentPlaceHolderID="phL" runat="Server"> <px:PXGrid ID="grid" runat="server" DataSourceID="ds" Width="100%" Height="150px" SkinID="Primary" AdjustPageSize="Auto" AllowPaging="True" AllowAutoHide="false"> <AutoSize Enabled="True" /> <Levels> <px:PXGridLevel DataMember="Processing"> <Columns> <px:PXGridColumn DataField="Selected" Type="CheckBox" Width="60" ></px:PXGridColumn> <px:PXGridColumn DataField="OrigSrvOrdNbr" Width="150" ></px:PXGridColumn> <px:PXGridColumn DataField="LineNbr" Width="70" ></px:PXGridColumn> <px:PXGridColumn DataField="InventoryID" Width="75" ></px:PXGridColumn> <px:PXGridColumn DataField="FDUnitPrice" Width="75" ></px:PXGridColumn> <px:PXGridColumn DataField="FSUnitPrice" Width="75" ></px:PXGridColumn> </Columns> </px:PXGridLevel> </Levels> <AutoSize Container="Window" Enabled="True" MinHeight="150" /> <ActionBar > </ActionBar> </px:PXGrid> </asp:Content>
解决方案
1. 修正DAC字段的抽象类顺序
Acumatica要求DAC的抽象类必须在对应属性之前定义,否则BQL无法正确解析字段,导致非键字段加载失败。调整所有字段的定义顺序:
#region FDUnitPrice public abstract class fDUnitPrice : PX.Data.BQL.BqlDecimal.Field<fDUnitPrice> { } [PXDBDecimal(4, BqlField = typeof(FSAppointmentDet.unitPrice))] [PXUIField(DisplayName = "Appt Price")] public virtual decimal? FDUnitPrice { get; set; } #endregion #region From the FSSODet DAC #region FSRefNbr public abstract class fSRefNbr : PX.Data.BQL.BqlString.Field<fSRefNbr> { } [PXDBString(20, IsUnicode = true, BqlField = typeof(FSSODet.refNbr))] public virtual string FSRefNbr { get; set; } #endregion #region FSLineNbr public abstract class fSLineNbr : PX.Data.BQL.BqlInt.Field<fSLineNbr> { } [PXDBInt(BqlField = typeof(FSSODet.lineNbr))] public virtual int? FSLineNbr { get; set; } #endregion #region FSUnitPrice public abstract class fSUnitPrice : PX.Data.BQL.BqlDecimal.Field<fSUnitPrice> { } [PXDBDecimal(4, BqlField = typeof(FSSODet.unitPrice))] [PXUIField(DisplayName = "SO Price")] public virtual decimal? FSUnitPrice { get; set; } #endregion #region TranDesc public abstract class tranDesc : PX.Data.BQL.BqlString.Field<tranDesc> { } [PXDBString(255, IsUnicode = true, BqlField = typeof(FSSODet.tranDesc))] public virtual string TranDesc { get; set; } #endregion #endregion
2. 移除ASPX中的无效列
ASPX网格中配置了InventoryID字段,但DAC中未定义该字段,会导致页面渲染错误,直接移除该列:
<Columns> <px:PXGridColumn DataField="Selected" Type="CheckBox" Width="60" ></px:PXGridColumn> <px:PXGridColumn DataField="OrigSrvOrdNbr" Width="150" ></px:PXGridColumn> <px:PXGridColumn DataField="LineNbr" Width="70" ></px:PXGridColumn> <px:PXGridColumn DataField="FDUnitPrice" Width="75" ></px:PXGridColumn> <px:PXGridColumn DataField="FSUnitPrice" Width="75" ></px:PXGridColumn> </Columns>
3. 在处理例程中重新加载完整记录
PXProcessing传递给委托的对象仅包含键值字段,需要通过键值重新从缓存或数据库获取完整的Projection记录:
static private void ProcessItem(PriceProjDAC item, PXCache onCache) { if (item.Selected == true) { // 通过键值重新加载完整记录 PriceProjDAC fullItem = onCache.GetItem(item) as PriceProjDAC; if (fullItem == null) { // 缓存中无数据时从数据库查询 fullItem = PXSelect<PriceProjDAC, Where<PriceProjDAC.srvOrdType, Equal<Required<PriceProjDAC.srvOrdType>>, And<PriceProjDAC.refNbr, Equal<Required<PriceProjDAC.refNbr>>, And<PriceProjDAC.lineNbr, Equal<Required<PriceProjDAC.lineNbr>>>>>> .Select(onCache.Graph, item.SrvOrdType, item.RefNbr, item.LineNbr); } if (fullItem != null) { // 注意:Projection是只读视图,需直接更新源DAC(FSSODet) FSSODet soDet = PXSelect<FSSODet, Where<FSSODet.refNbr, Equal<Required<FSSODet.refNbr>>, And<FSSODet.lineNbr, Equal<Required<FSSODet.lineNbr>>>>> .Select(onCache.Graph, fullItem.OrigSrvOrdNbr, fullItem.FSLineNbr); if (soDet != null) { soDet.UnitPrice = fullItem.FDUnitPrice; onCache.Graph.Caches[typeof(FSSODet)].Update(soDet); onCache.Graph.Actions.PressSave(); } } } }
关键原因总结
- DAC字段的抽象类顺序错误,导致BQL无法解析非键字段,加载时丢失数据;
- ASPX中存在未定义的列,干扰页面数据渲染;
- PXProcessing默认仅传递键值字段,需手动重新加载完整记录才能获取非键字段的值。
内容的提问来源于stack exchange,提问作者MarkJoel60
相关产品推荐
相关产品推荐

