AxInternalBase API
创建Ax<Table>类的目的是当创建和更新AX表中的记录时有一个可用的API。AxInternalBase API的设计目标如下:
1.该API易于使用
2.该API必须处理相关字段。当一个字段更新时可以应用默认值。比如,当更改销售订单的客户账户时,将地址字段从客户记录复制到销售订单记录时,地址字段应该可以用默认值
3.该API必须处理字段更新的顺序。比如,发票帐号字段是一个相关字段,当客户账户改变时,该字段应该变成默认值。
4.字段默认值可能不总是提供期望的最终结果。考虑一个例子:首先更新如果发票帐号,其他字段的值是默认的,然后更新客户帐号,其他字段的值是默认的,这样默认值将会重写显式提供的发票帐号字段。
5.该API必须能从编码规则取得编码或者标识符。比如,当创建一个销售订单时,销售订单号必须从销售订单的编码规则中取得。处理这些的逻辑在这些类中实现。
新的Ax<Table>类必须继承自AxInternalBase类。AxInternalBase类追踪为了给表的某个字段设定一个特定的值都执行了哪些方法,可以外部或者内部实现追踪。外部的,比如,可以用一个特定的值调用AxSalesTable类的parmCustAccount方法。内部的,可以调用AxSalesTable的parmInvoiceAccount方法,因为它是个相关字段,当parmCustAccount 方法执行时,它应该变成默认值。通过监测执行的方法,AxinternalBase类确保外部设定的值不被重写。
类AxBC(译注:上下文都没提到过AxBC这个东东,应该就是Ax<Table>类)的声明中必须声明一个与AxBC相关的表类型的记录变量。因此AxSalesTable的类声明如下所示:
class AxSalesTable extends AxInternalBase
{
SalesTable salesTable;
}
public DataType parmFieldName(DataType _fieldName
= literal)
{
if (!prmisdefault(_fieldName))
{
this.setField(fieldNum(TableName,FieldName), _fieldName);
}
return tableName.fieldName;
}类AxInternalBase的实例方法setField查看该字段是否已经被设定了某个特定的值,如果没有设定会给该字段分配当前值。同时,更新其他已经分配了值的一系列字段。setField方法的逻辑如9-4所示。

图9-4.setField方法的逻辑流程图
在类AxSalesTable的parmCustAccount方法体中可以看一个setField方法的具体实现(译注:原文缩减了该方法,这里将方法体全部列出):
public str parmCustAccount(str _custAccount = '')
{
DictField dictField;
;
if (!prmisdefault(_custAccount))
{
dictField = new DictField(tablenum(SalesTable),fieldnum(SalesTable, CustAccount));
if(this.valueMappingInbound())
{
this.validateInboundString(_custAccount, dictField, this.mapPolicy().xMLMapCustAccount());
_custAccount = this.axCustAccount(_custAccount);
}
else
{
this.validateInboundString(_custAccount, dictField);
}
this.setField(fieldnum(SalesTable, CustAccount), _custAccount);
}
if (this.valueMappingOutbound())
{
return this.axCustAccount(salesTable.CustAccount);
}
else
{
return salesTable.CustAccount;
}
}
protected void setFieldName()
{
if (this.isMethodExecuted(funcName(), fieldNum
(TableName, FieldName)))
{
return;
}
// Additional code goes here.
}
图9-5.方法isMethodExecuted 的逻辑流程
如果依赖于其他字段(译注:原文为Dependencies on other fields ,意思是如果当前字段依赖于其他字段的话,就按如下方式执行)必须按如下方式编程
this.setAnotherFieldName();
if (this.isFieldSet(fieldNum(TableName,
AnotherFieldName)))
{
this.fieldName(newValue);
}
protected void setPaymMode()
{
if (this.isMethodExecuted(funcname(), fieldnum(SalesTable, PaymMode)))
{
return;
}
this.setInvoiceAccount();
if (this.isFieldSet(fieldnum(SalesTable, InvoiceAccount)))
{
this.parmPaymMode(this.invoiceAccount_CustTableRecord().PaymMode);
}
}为了设置和获取当前记录,必须重写类AxSaelsTable的currentRecord 方法。重写必须使用如下模板
protected TableName currentRecord(TableName
_tableName = tableName)
{
if (!prmisdefault(_tableName))
{
super(_tableName);
tableName = _tableName;
}
else
{
super();
}
return tableName;
}
图9-6.currentRecord 方法的逻辑流程
可以看一下类AxSalesTable的currentRecord方法的实现:
protected SalesTable currentRecord(SalesTable
_salesTable = salesTable)
{
if (!prmisdefault(_salesTable))
{
super(_salesTable);
salesTable = _salesTable;
}
else
{
super();
}
return salesTable;
}
public TableName tableName(TableName _tableName = tableName)
{
if (!prmisdefault(_tableName))
{
this.setCurrentRecordFromExternal(_tableName);
}
return this.currentRecord();
}为确保在插入或更新记录之前调用所有的默认方法,必须重写类AxInternalBase 的setTableFields 方法,该方法应包含对所有默认方法的调用。可以看一下类AxSalesTable 的setTableFields 方法的部分实现:
protected void setTableFields()
{
SalesTableLinks salesTableLinks;
;
super();
useMapPolicy = false;
this.setCashDisc();
this.setCommissionGroup();
this.setContactPersonId();
this.setCurrencyCode();
this.setCustAccount();
this.setCustGroup();
this.setDeliveryAddress();
this.setDeliveryCity();
// And so on

