Поля-формулы: циклическая ссылка

Формула поля может читать поля связанной записи, даже если эта запись принадлежит той же таблице. Но прочитать собственное поле в этой записи она не может: редактор формул отклоняет её с сообщением «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.
  • Цикл может проходить и через два поля: Members, читающее Parent.'Effective members', образовало бы петлю Members → Effective members → Members. Мы не проверяли, как Ninox обрабатывает этот случай: избегайте его тем же способом.