PXFormula 属性
一般说明
Acumatica 中的公式是 DAC 字段,它是根据其他对象字段的值计算的。
为了计算公式,Aсumatiсa 框架提供了一组各种操作和函数(例如算术,逻辑和比较运算以及字符串处理函数;请参阅内置公式列表 )。除了字段值之外,公式还可以使用 Acumatica 核心和应用程序解决方案提供的各种常量。此外,公式不仅可以从当前记录中获得计算值,还可以从其他来源获得计算值(请参阅公式上下文及其修饰符 )。
公式的美妙之处在于它们会在适当的时间自动重新计算价值:
- 字段默认(插入新行;公式字段的
FieldDefaulting
事件处理程序) - 关于依赖字段的更新(每个依赖字段的
FieldUpdated
事件处理程序) - 关于数据库选择(仅适用于未绑定字段;
RowSelecting
事件处理程序) - 在需要时保持数据库持久化(开发人员应明确指定它;
RowPersisted
事件处理程序)
在依赖字段的更新上重新计算公式字段值会引发公式字段的 FieldUpdated
事件。这允许你创建一系列相关公式(请参阅公式中的直接和中介循环引用)。
应用程序开发人员可以编写自己的应用程序端公式
使用方式
公式可以用于三种主要模式:
- 只需计算值并将其分配给公式字段(请参阅基本用法 )
- 从公式字段的现有值计算聚合值并将其分配给父对象中的指定字段(请参阅聚合用法 )
- 混合模式:计算公式值,将其分配给公式字段,计算聚合值,并将其分配给父对象中的字段(请参阅组合使用 )
还有另一种辅助模式,未绑定的公式,与混合模式非常相似,但公式的计算值未分配给公式字段。立即计算聚合值并将其分配给父对象的字段。有关详细信息,请参阅未绑定公式的用法。
PXFormulaAttribute
属性和构造函数参数
公式功能由 PXFormulaAttribute
实现。PXFormulaAttribute 的构造函数具有以下签名:
public PXFormulaAttribute(Type formulaType)
{
// ...
}
单个参数 formulaType
是一种公式表达式,用于计算来自同一数据记录的其他字段的字段值。此参数必须满足以下条件之一:
- 必须实现 IBqlField 接口
- 必须是 BQL 常量
- 必须实现 IBqlCreator 接口(参见内置常用公式列表 )
public PXFormulaAttribute(Type formulaType, Type aggregateType)
{
// ...
}
第一个参数 formulaType
与第一个构造函数中的相同。第二个参数 aggregateType
是一种聚合公式,用于计算子数据记录字段中的父数据记录字段。可以使用聚合函数,例如 SumCalc,CountCalc,MinCalc 和 MaxCalc。应用开发人员可以创建自己的聚合公式。
聚合公式类型必须是泛型类型,并且必须实现 IBqlAggregateCalculator
接口。聚合公式类型的第一个通用参数必须实现 IBqlField
接口,并且必须具有父对象的字段类型。
public virtual bool Persistent { get; set; }
PXFormulaAttribute.Persistent
属性指示在将更改保存到数据库后属性是否重新计算公式。如果在 RowPersisting
事件中更新了公式所依赖的字段,则可能需要重新计算。默认情况下,该属性等于 false
。
用法
在大多数情况下,公式用于直接计算来自同一数据记录的其他字段的公式字段的值。
最简单的公式用法示例:
[PXDBDate]
[PXFormula(typeof(FADetails.receiptDate))]
[PXDefault]
[PXUIField(DisplayName = Messages.PlacedInServiceDate)]
public virtual DateTime? DepreciateFromDate { get; set; }
在此示例中,ReceiptDate 字段的值在插入新记录和 ReceiptDate 字段更新时分配给 DepreciateFromDate 字段。
一个稍微复杂的例子:
[PXCurrency(typeof(APPayment.curyInfoID), typeof(APPayment.unappliedBal))]
[PXUIField(DisplayName = "Unapplied Balance", Visibility = PXUIVisibility.Visible, Enabled = false)]
[PXFormula(typeof(Sub<APPayment.curyDocBal, APPayment.curyApplAmt>))]
public virtual Decimal? CuryUnappliedBal { get; set; }
这里,文档的未应用余额计算为文档余额与应用金额之间的差额。
具有默认值的多项选择示例:
[PXUIField(DisplayName = "Class Icon", IsReadOnly = true)]
[PXImage]
[PXFormula(typeof(Switch<
Case<Where<EPActivity.classID, Equal<CRActivityClass.task>>, EPActivity.classIcon.task,
Case<Where<EPActivity.classID, Equal<CRActivityClass.events>>, EPActivity.classIcon.events,
Case<Where<EPActivity.classID, Equal<CRActivityClass.email>,
And<EPActivity.isIncome, NotEqual<True>>>, EPActivity.classIcon.email,
Case<Where<EPActivity.classID, Equal<CRActivityClass.email>,
And<EPActivity.isIncome, Equal<True>>>, EPActivity.classIcon.emailResponse,
Case<Where<EPActivity.classID, Equal<CRActivityClass.history>>, EPActivity.classIcon.history>>>>>,
Selector<Current2<EPActivity.type>, EPActivityType.imageUrl>>))]
public virtual string ClassIcon { get; set; }
领域顺序
DAC 中的字段顺序对于校正公式计算很重要。必须在公式字段之前的 DAC 中定义包括其他公式的所有源字段(从中计算公式)。否则,可能会错误地计算字段,或者可能导致运行时错误。
公式语境及其修饰语
默认情况下,公式计算的上下文受包含公式声明的类的当前对象(记录)限制。它也允许使用常量(Constant<>
类的后代)。
仅使用其对象字段的公式:
public partial class Contract : IBqlTable, IAttributeSupport
{
//...
[PXDecimal(4)]
[PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)]
[PXFormula(typeof(Add<Contract.pendingRecurring, Add<Contract.pendingRenewal, Contract.pendingSetup>>))]
[PXUIField(DisplayName = "Total Pending", Enabled=false)]
public virtual decimal? TotalPending { get; set; }
//...
}
但是,可以从其他来源获取公式计算的输入值:
- BLC 中任何缓存的当前记录(如果已分配)。
PXSelectorAttribute
指定的外国记录。- 由
PXParentAttribute
指定的父记录。
该公式支持以下上下文修饰符。
Current<TRecord.field>
和 Current2<TRecord.field>
从存储在 TRecord 缓存的 Current
属性中的记录中获取字段值。
如果缓存的 Current
属性或字段本身包含 null:
- 当前<>强制字段默认并返回默认字段值。
- Current2 <>返回 null。
例:
[PXFormula(typeof(Switch<
Case<Where<
ARAdjust.adjgDocType, Equal<Current<ARPayment.docType>>,
And<ARAdjust.adjgRefNbr, Equal<Current<ARPayment.refNbr>>>>,
ARAdjust.classIcon.outgoing>,
ARAdjust.classIcon.incoming>))]
protected virtual void ARAdjust_ClassIcon_CacheAttached(PXCache sender)
Parent<TParent.field>
从驻留在当前 DAC 上的 PXParentAttribute 定义的父数据记录中获取字段值。
public class INTran : IBqlTable
{
[PXParent(typeof(Select<
INRegister,
Where<
INRegister.docType, Equal<Current<INTran.docType>>,
And<INRegister.refNbr,Equal<Current<INTran.refNbr>>>>>))]
public virtual String RefNbr { ... }
[PXFormula(typeof(Parent<INRegister.origModule>))]
public virtual String OrigModule { ... }
}
IsTableEmpty<TRecord>
如果对应于指定 DAC 的 DB 表不包含记录,则返回 true
,否则返回 false
。
public class APRegister : IBqlTable
{
[PXFormula(typeof(Switch<
Case<Where<
IsTableEmpty<APSetupApproval>, Equal<True>>,
True,
Case<Where<
APRegister.requestApproval, Equal<True>>,
False>>,
True>))]
public virtual bool? DontApprove { get; set; }
}
Selector<KeyField, ForeignOperand>
获取在当前 DAC 的外键字段(KeyField)上定义的 PXSelectorAttribute
获取选择器当前引用的外部数据记录
计算并返回 ForeignOperand 定义的数据记录上的表达式
public class APVendorPrice : IBqlTable
{
// Note: inventory attribute is an
// aggregate containing a PXSelectorAttribute
// inside, which is also valid for Selector<>.
// -
[Inventory(DisplayName = "Inventory ID")]
public virtual int? InventoryID
[PXFormula(typeof(Selector<
APVendorPrice.inventoryID,
InventoryItem.purchaseUnit>))]
public virtual string UOM { get; set; }
}
在未绑定字段上使用公式
如果公式字段是标记有 PXFieldAttribute
后代之一的未绑定字段(例如 PXIntAttribute
或 PXStringAttribute
),则在 RowSelecting
事件期间另外触发其计算。
内置常用公式列表
TBD
公式中的直接和中介循环引用
TBD
条件公式中的控制流程
TBD
在一个场上使用多个公式
TBD