公式字段:循环引用

字段公式可以读取关联记录的字段,即使该记录属于同一张表。但它不能读取该记录上的自身字段:公式编辑器会拒绝它,并显示消息“Circular reference”。

示例

表 Groups 有一个指向自身的引用 Parent:子组通过它指向所属的组。公式字段 Members 选出某个国家的人员(Country filter),而子组必须从其所属组的成员中选取自己的成员:

Ninox
let country := 'Country filter';
let candidates := if Parent then Parent.Members else select People end;
candidates[Country = country]

公式编辑器拒绝这段代码:“Circular reference: Members”。

原因

Ninox 按字段而不是按记录来推理。要编译 Members 的公式,它必须知道 Parent.Members 的类型,因此要编译 Members 的公式……而这正是它此刻在编译的公式。父记录永远不会是记录本身,这一点无关紧要:这种依赖在编译时就被拒绝了。

注意

同一个表达式通过编程接口(/query)求值时,或者放在另一个字段的公式中时,都不会报错。只有它所读取的那个字段的公式编辑器会拒绝它:因此,在别处测试成功并不能保证它会被接受。

解决方法:第二个字段

让 Members 在不读取父组的情况下计算其列表:

Ninox
let country := 'Country filter';
select People where Country = country

然后把限制交给第二个公式字段 Effective members,它读取记录本身及其父记录上的 Members:

Ninox
if Parent then
    let parentMembers := Parent.Members;
    Members[contains(parentMembers, this)]
else
    Members
end

Effective members 读取 Members,但 Members 不读取 Effective members:不再有循环。在方括号内,this 指正在检查的人员;因此父记录的成员要事先读入一个变量。

须知

  • 子组的 Members 字段现在包含不属于该组的人员:所有显示或使用成员的地方(视图、按钮、全局函数)都必须读取 Effective members。
  • 循环也可能经过两个字段:读取 Parent.'Effective members' 的 Members 会形成 Members → Effective members → Members 的循环。我们没有验证 Ninox 如何处理这种情况:请用同样的方法避免它。