LINQ分层查询返回所有父项

时间:2014-05-18 10:53:16

标签: c# asp.net-mvc linq parent hierarchical

我坚持在LINQ中进行分层查询 - 我正在进行我的第一个ASP.NET项目,因此缺乏知识和经验。我基本上在EF6,C#和MVC 5上做项目。 所以,我无法弄清楚如何获得以下分层数据。

我有一个员工表,一个employeeMap表和一个目标表。 EmployeeMap将目标映射到员工。目标是分层的,所以目标在一元关系中有一个父目标,这里我的目标类有点简化:

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将为null。这是我的目标和直接父母的查询。

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();
        }

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

谢谢:)

1 个答案:

答案 0 :(得分:0)

是否必须是单个查询?从数据层服务调用方法后,可能会返回列表:

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查询效率低得多,因为这个查询有多个命中数据库。要保存数据库命中,您还可以先在内存中构建表,然后从那些表中查询(如果是首选)。

希望它有助于或至少为可行的解决方案提供一些想法。