LINQ层次查询返回所有父级

本文关键字:返回 层次 查询 LINQ | 更新日期: 2023-09-27 18:04:06

我坚持在LINQ做分层查询-我在我的第一个ASP。NET项目,所以忍受我的知识和经验的缺乏。我基本上在EF6, c#和MVC 5上做项目。所以,我不知道如何得到下面的分层数据。

我有一个雇员表、一个employeeMap表和一个Goal表。EmployeeMap将目标映射到员工。目标是分层的,一个目标有一个父目标,在一个一元关系中,这里我的goal类稍微简化了一下:

public class Goal
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int? ParentID { get; set; }
    public virtual Goal Parent { get; set; }
}

我需要一个映射到员工的目标列表,以及它的所有父目标。我可以把目标映射到雇员,以及它的父目标,但不能把父目标映射到父目标等等,在层次结构的顶端,parentID将为空。这是我的查询得到目标和直接父。

viewModel.EmpGoals = (
         from g in db.Goals
         join m in db.EmployeeMaps on g.ID equals m.GoalID
         join e in db.Employees on m.EmployeeID equals e.ID
         where m.EmployeeID == id.Value
         select new EmployeeGoal
         {
             EmployeeID = e.ID,
             LastName = e.LastName,
             FirstName = e.FirstName,
             GoalID = g.ID,
             Name = g.Name,
             ParentID = g.ParentID,
             Parent = g.Parent,
             WeightPct = m.WeightPct,
             Locked = m.State.Equals(1),
             Activities = g.Activities
         }).ToList();
        }

所以我想我需要一个分层查询,递归地运行到所有的父,并返回每个父(或至少只是父树的顶部,或根可能更大),但我怎么能做到这一点使用LINQ,或者我应该考虑一些原始SQL给我这个回来?

谢谢:)

LINQ层次查询返回所有父级

是否必须是单个查询?也许从你的数据层服务调用一个方法后返回你的列表:

ExampleDataLayerService dlSvc = new ExampleDataLayerService();
viewModel.EmpGoals = dlSvc.GetEmpGoalList(id.Value);

服务层方法:

public List<EmployeeGoal> GetEmpGoalList(int empID)
{
    //Get employee info
    var empInfo = db.Employees.Where(x => x.ID == empID).Select(x => new { ID = x.ID, LastName = x.LastName, Firstname = x.FirstName }).FirstOrDefault();
    //Get initial bottom tier list of employee goals
    List<int> goalIdList = db.EmployeeMaps.Where(x => x.EmployeeID == empID).Select(x => x.GoalID).ToList();
    List<EmployeeGoal> empGoalList = new List<EmployeeGoal>();
    List<int> usedGoalList = new List<int>();
    foreach (var goal in goalIdList)
    {
        var tempID = goal;
        while (tempID != 0 && tempID != null)
        {
            var gmData = (from g in db.Goals
                      join m in db.EmployeeMaps.Where(m => m.EmployeeID == empInfo.ID) on g.ID equals m.GoalID into m_g
                      from mg in m_g.DefaultIfEmpty()
                      where g.Goals == tempID
                      select new EmployeeGoal
                      {
                          EmployeeID = empInfo.ID,
                          LastName = empInfo.LastName,
                          FirstName = empInfo.FirstName,
                          GoalID = g.ID,
                          Name = g.Name,
                          ParentID = g.ParentID,
                          Parent = g.Parent,
                          WeightPct = (mg == null) ? 0 : mg.WeightPct,
                          Locked = (mg == null) ? 0 : mg.State.Equals(1),
                          Activities = g.Activities
                      }).FirstOrDefault();
            if (!usedGoalList.Contains(gmData.GoalID))
            {
                empGoalList.Add(gmData);
                UsedGoalList.Add(gmData.GoalID);
            }
            tempID = gmData.ParentId;
        }
    }
    return empGoalList;
}

代码是未经测试的,所以可能不能按原样运行。如果需要的话,你还可以添加一些元数据来确定每个目标的"层",如果你需要从根向下排序目标列表或类似的东西。此外,这个解决方案可能不起作用,因为它将比单个LINQ查询效率低得多,因为这个查询有多个数据库。为了保存DB命中,您也可以先在内存中构建表,然后根据需要从这些表中进行查询。

希望能有所帮助,或者至少能给出一些可行的解决方案