Перейти к содержанию

Записи и коллекции. Рекурсивная выборка записей из иерархических коллекций с помощью N3

Введение

Атрибут типа «Запись» хранит ID записей в связанном шаблоне (ссылки на них).

Зачастую требуется предоставлять пользователю для выбора списки записей, объединённые из нескольких шаблонов и отфильтрованные по сложным правилам. Например, когда данные находятся в иерархически связанных справочниках.

Для работы с иерархическими структурами в N3 доступны две функции обхода иерархии:

  • object:getRootByParentProperty — выполняет восходящий обход иерархии (от дочерней записи к корневой через цепочку родительских записей) и возвращает корневую запись;
  • object:getRootByChildProperty — выполняет нисходящий обход иерархии (от текущей записи по цепочке ко всем дочерним) и возвращает список всех найденных дочерних записей.

Здесь представлены примеры использования этих функций для выборки записей из иерархических коллекций.

Прикладная задача

  • В системе кадрового учёта имеется следующая иерархическая оргструктура:

    Компания 
    └── Департамент
    └── Сотрудники компании
    └── Отдел
    └── Сотрудники департамента
    └── Группа
    └── Сотрудники отдела
  • Любое подразделение может содержать ссылки на произвольное количество дочерних подразделений и аккаунтов сотрудников.

Требуется:

  1. Найти корневое подразделение (Компанию), начиная от выбранного подразделения и двигаясь вверх по иерархии (восходящий обход).
  2. Найти все дочерние подразделения, начиная от выбранного подразделения и двигаясь вниз по иерархии (нисходящий обход).
  3. Получить список всех сотрудников, работающих в найденных подразделениях.

Исходные данные

Имеются шаблоны записей «Оргструктура» и «Сотрудники».

  • В шаблоне записи «Оргструктура» хранится организационная структура компании.

    Атрибуты в шаблоне:

    • Родительское подразделение
    • Описание: Ссылка на родительское подразделение в иерархии
    • Тип данных: запись
    • Связанный шаблон: Оргструктура
    • Хранить несколько значений: флажок снят
    • Дочернее подразделение
    • Описание: Коллекция дочерних подразделений в иерархии
    • Тип данных: запись
    • Связанный шаблон: Оргструктура
    • Хранить несколько значений: флажок установлен
    • Сотрудники
    • Описание: Коллекция сотрудников, работающих в подразделении
    • Тип данных: запись
    • Связанный шаблон: Сотрудники
    • Хранить несколько значений: флажок установлен
    • В шаблоне записи «Сотрудники» хранится информация о сотрудниках организации.

    Атрибуты в шаблоне:

    • Подразделение
    • Описание: Ссылка на подразделение, в котором работает сотрудник
    • Тип данных: запись
    • Связанный шаблон: Оргструктура
    • Хранить несколько значений: флажок снят
    • Аккаунт
    • Описание: Ссылка на аккаунт сотрудника
    • Тип данных: аккаунт
    • Связанный шаблон: Сотрудники
    • Хранить несколько значений: флажок снят

Практический пример: получение компании, к которой относится текущее подразделение

Для вычисления корневого подразделения воспользуемся функцией восходящего обхода иерархической коллекции записей object:getRootByParentProperty.

  1. Откройте шаблон записи «Оргструктура».
  2. Создайте атрибут «Компания» со следующими свойствами:
  • Описание: Компания
  • Тип данных: запись
  • Связанный шаблон: Оргструктура
  • Хранить несколько значений: флажок снят
  • Вычислять автоматически: флажок установлен
  1. Введите следующее вычисляемое значение на языке N3:

    @prefix object: <http://comindware.com/ontology/object#>. 

    {
    # Убедитесь, что системные имена соответствуют именам в вашем приложении.
    # Получаем атрибут, который ссылается на родительское подразделение
    ("Оргструктура" "Родительскоеподразделение") object:findProperty ?ParentDepartmentAttribute.

    # Получаем корневую запись с помощью восходящего обхода
    # родительских записей от текущей записи (?item)
    (?item ?ParentDepartmentAttribute) object:getRootByParentProperty ?RootDepartment.

    # Возвращаем корневую запись
    ?RootDepartment -> ?value.
    }
  2. Поместите атрибут «Компания» на форму шаблона «Оргструктура».

Логика работы функции object:getRootByParentProperty

Функция object:getRootByParentProperty обходит цепочку родительских записей от текущей записи, пока не найдёт запись без родительской записи (то есть корневую запись) и возвращает найденную корневую запись.

  • Синтаксис:

    (?startRecord ?parentAttribute) object:getRootByParentProperty ?returnValue. 
  • Аргументы:

    • ?startRecord — начальная запись, от которой начинается обход;
    • ?parentAttribute — атрибут, ссылающийся на родительскую запись;
    • ?returnValue — возвращаемое значение.
  • Пример иерархии при восходящем обходе:

    Компания (корневая запись) 
    └─ Департамент
    └─ Отдел
    └─ Группа (начальная запись — ?startRecord)

    При вызове функции с начальной записью «Группа» функция вернёт запись «Компания».

Практический пример: получение списка всех сотрудников текущего подразделения и его дочерних подразделений

Для получения списка всех сотрудников, работающих в текущем подразделении и всех его дочерних подразделениях, воспользуемся функцией нисходящего обхода иерархической коллекции записей object:getRootByChildProperty.

  1. Откройте шаблон записи «Оргструктура».
  2. Создайте атрибут «Все сотрудники» со следующими свойствами:
  • Описание: Список всех сотрудников в текущем подразделении и всех его дочерних подразделениях
  • Тип данных: запись
  • Связанный шаблон: Сотрудники
  • Хранить несколько значений: флажок установлен
  • Вычислять автоматически: флажок установлен
  1. Введите следующее вычисляемое значение на языке N3:

    @prefix object: <http://comindware.com/ontology/object#>. 
    @prefix list: <http://www.w3.org/2000/10/swap/list#>.

    {
    # Убедитесь, что системные имена соответствуют именам в вашем приложении.
    # Получаем атрибуты для дальнейших вычислений
    ("Оргструктура" "Дочернееподразделение") object:findProperty ?ChildDepartmentAttribute.
    ("Оргструктура" "Сотрудники") object:findProperty ?EmployeesAttribute.

    # Получаем все дочерние подразделения с помощью нисходящего обхода
    # от текущей записи (?item) до конечной без дочерних подразделений
    (?item ?ChildDepartmentAttribute) object:getRootByChildProperty ?ChildDepartments.

    # Получаем всех сотрудников из всех найденных подразделений
    ?ChildDepartments ?EmployeesAttribute ?Employees.

    # Возвращаем список найденных сотрудников
    ?Employees -> ?value.
    }
  2. Поместите атрибут «Все сотрудники» на форму шаблона «Оргструктура».

Логика работы функции object:getRootByChildProperty

Функция object:getRootByChildProperty последовательно обходит цепочку дочерних записей от текущей записи, пока не встретит запись, у которой отсутствует дочерняя запись (то есть конечную запись). Функция возвращает список всех дочерних записей, найденных при обходе.

  • Синтаксис:

    (?startRecord ?childAttribute) object:getRootByChildProperty ?returnValue. 
  • Аргументы:

    • ?startRecord — текущая запись, от которой начинается обход;
    • ?childAttribute — атрибут, ссылающийся на дочерние записи;
    • ?returnValue — возвращаемое значение (список дочерних записей).
  • Пример иерархии для нисходящего обхода:

    Компания (начальная точка — ?item) 
    └─ Департамент
    └─ Отдел
    └─ Группа

    При вызове функции с начальной записью «Компания» функция вернёт список: [Компания, Департамент, Отдел, Группа].

К началу