简体   繁体   English

LINQ分层查询以返回所有父级

[英]LINQ Hierarchical query to return all parents

I am stuck on doing a hierarchical query in LINQ - I am on my first ASP.NET project ever, so bear over with my lack of knowledge and experience. 我一直坚持在LINQ中进行分层查询-我在有史以来第一个ASP.NET项目中,所以请以我缺乏的知识和经验来承受。 I am basically doing the project on EF6, C#, and MVC 5. So, I can't figure out how to get the following hierarchical data out. 我基本上是在EF6,C#和MVC 5上进行项目的。因此,我不知道如何获取以下分层数据。

I have an employee table, an employeeMap table, and a Goal table. 我有一个雇员表,一个employeeMap表和一个目标表。 EmployeeMap maps goals to employees. EmployeeMap将目标映射到员工。 Goals are hierarchical so, a goal has a parent goal in an unary relationship, here my Goal class a little simplified: 目标是分层的,因此,目标在一元关系中具有父目标,在这里我的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; }
}

I need a list of goals mapped to an employee, and all the parent goals thereof. 我需要一个映射到一名员工的目标及其所有父目标的列表。 I can get the goals mapped to the employee, and the parent goal thereof, but can't get the parents parent and so on up the hierarchy to the top, where parentID would be null. 我可以获取映射到员工的目标及其父目标,但无法获取父父,等等,直到层次结构到达最顶层为止,其中parentID为null。 Here's my query getting the goals and the direct parent. 这是我查询的目标和直接父级。

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

So I guess I need a hierarchical query, recursively running up to all parents and return each parent ( or at least just the very top of the parent tree, or root maybe rather), but how can I do that using LINQ, or should I consider some raw SQL to give me this back? 所以我想我需要一个层次查询,递归地运行到所有父节点并返回每个父节点(或者至少是父树的最顶端,或者甚至是根),但是我该如何使用LINQ做到这一点呢?考虑一些原始SQL给我这个吗?

Thanks :) 谢谢 :)

Does it have to be a single query? 是否必须是单个查询? Maybe return your list after calling a method from your data layer service: 从数据层服务调用方法后,可能会返回列表:

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

Service layer method: 服务层方法:

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

Code is off the top of my head an untested so may not run as is. 代码是未经测试的,因此可能无法按原样运行。 If desired you could also add some meta data to determine what "tier" each goal is if you need to sort the goal list from root downwards or something like that. 如果需要,您还可以添加一些元数据来确定每个目标是什么“层”,如果您需要从根向下或类似的东西对目标列表进行排序。 Also this solution may not work as it will be much less efficient than a single LINQ query as this one has multiple hits the DB. 同样,该解决方案可能不起作用,因为它比单个LINQ查询效率低得多,因为该查询具有多个命中数据库。 To save DB hits you can also just build the tables in memory first and query from those if that's preferred. 要保存数据库命中,您还可以先在内存中构建表,然后从中查询(如果需要)。

Hope it helps or at least gives some ideas for a workable solution. 希望它有助于或至少给出一些可行解决方案的想法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM