Рефакторинг кода формирования дерева из бд
У меня есть код получения отделов и сотрудников, надо вывести дерево. В целом код работает, но я бы хотел избавиться от параметра nested без которого я ухожу в бесконечный цикл, как это можно сделать? Сразу оговорюсь что мне не нужны сторонние библиотеки которые умеют работать с деревьями в бд! Если id = null значит отдел главный. Циклов в отделах нет. Еще в модели Department нет коллекции подотделов, есть только id родителя
//nested - костыль для того чтобы не уйти в беск цикл
//если true - то надо доставать по parentId, иначе по id.
private async Task<List<DepartmentTreeItem>> CreateTreeAsync(int? id, bool nested)
{
var queryableDepartment = (await _departmentRepository.GetQueryableAsync())
.OrderBy(x => x.Name);
var employeeQueryable = (await _employeeRepository.GetQueryableAsync())
.OrderBy(x => x.FullName);
List<Department> list = new List<Department>();
if (id != null && !nested)
{
list = queryableDepartment
.Where(x => x.Id == id)
.ToList();
}
else
{
list = queryableDepartment
.Where(x => x.ParentDepartmentId == id)
.ToList();
}
List<DepartmentTreeItem> result = new List<DepartmentTreeItem>();
foreach (var item in list)
{
List<EmployeeItem> employees = new List<EmployeeItem>();
employees = employeeQueryable.Where(x => x.DepartmentId == item.Id)
.Select(x => new EmployeeItem(x.Id, x.FullName))
.ToList();
var child = new DepartmentTreeItem
{
Id = item.Id,
Name = item.Name,
Employees = new Collection<EmployeeItem>(employees)
};
var manager = child.Employees.FirstOrDefault(x => x.Id == item.ManagerId);
if (manager != null)
{
child.Employees.Remove(manager);
child.Manager = manager;
}
var items = await CreateTreeAsync(child.Id, true);
result.Add(child);
child.Departments = new Collection<DepartmentTreeItem>(items);
}
return result;
}
Ответы (1 шт):
Я бы предложил просто вычитать из БД все данные и по ним сразу всё построить, без рекурсий и прочих сложностей.
Раз вы не привели модели, я их придумал как то так
class Department
{
public int Id;
public string Name;
public int ParentDepartmentId;
}
class Employee
{
public int Id;
public string FullName;
public int DepartmentId ;
}
class DepartmentTreeItem
{
public int Id;
public string Name;
public List<DepartmentTreeItem> Departments;
public List<EmployeeItem> Employees;
}
class EmployeeItem
{
public int Id;
public string FullName;
}
Функция, которая получает данные уже вычитанные из БД и компонует дерево
private List<DepartmentTreeItem> CreateTree(List<Department> deps, List<Employee> empl)
{
// делаем список департаментов в дерево
var treeDepartments = deps.Select(d => new DepartmentTreeItem() {
Id = d.Id,
Name = d.Name,
Employees = empl
.Where(e => e.DepartmentId == d.Id).Select(e => new EmployeeItem() {Id = e.Id, FullName = e.FullName})
.ToList()
}).ToList();
// проставляем департаментам дочерние департаменты
foreach(var group in deps.GroupBy(d=>d.ParentDepartmentId))
{
var tree = treeDepartments.Where(x=>x.Id == group.Key).Single();
tree.Departments = group
.Select(x=>treeDepartments.Where(z=>z.Id == x.Id).Single())
.ToList();
}
return treeDepartments;
}
Этот код вернет все отделы списком. Если вам надо только верхник узлы вернуть, добавьте фильтрацию в конце метода, тут
return treeDepartments; // замените тут на нужную вам фильтрацию