stackoverflowuser
stackoverflowuser

Reputation: 22380

linq to sql recursive query

EmployeeId  Name  ManagerId
------------------------------
1           A     null
2           B     null
3           C     1
4           D     3
5           E     2

just using this table, how can a linq query (using linq to sql) be written to fetch the parent data recursively.

For instance if the Employer Id selected is 4 it should give list of employees with Id: 4, 3, 1

Thanks.

Upvotes: 17

Views: 9981

Answers (4)

diceguyd30
diceguyd30

Reputation: 2752

I'm not sure if this is exactly what you want, but here is one recursive method that uses some linq that makes sure not to enter an infinite loop:

    public static IEnumerable<Employee> GetTreeForEmployeeNumber(this IEnumerable<Employee> source, int startingId) {
        var result = source.Where(x => x.EmployeeId == startingId).FirstOrDefault();
        if (result != null) {
            var resultAsE = new [] { result };
            if (!result.ManagerId.HasValue)
                return resultAsE;
            return resultAsE.Union(source.Except(resultAsE).GetTreeForEmployeeNumber(result.ManagerId.Value));
        }
        return new Employee [] { };
    }

If you have linqpad installed you can test this with the following script:

void Main()
{
    var lst = new [] {
        new Extensions.Employee{ EmployeeId = 1, Name = "A", ManagerId = null }, 
        new Extensions.Employee{ EmployeeId = 2, Name = "B", ManagerId = null }, 
        new Extensions.Employee{ EmployeeId = 3, Name = "C", ManagerId = 1 }, 
        new Extensions.Employee{ EmployeeId = 4, Name = "D", ManagerId = 3 }, 
        new Extensions.Employee{ EmployeeId = 5, Name = "E", ManagerId = 2 }
    };

    lst.GetTreeForEmployeeNumber(4).Dump();
}

public static class Extensions {

    public class Employee {
        public int EmployeeId { get; set; }
        public string Name { get; set; }
        public int? ManagerId { get; set; }
    }

    public static IEnumerable<Employee> GetTreeForEmployeeNumber(this IEnumerable<Employee> source, int startingId) {
        var result = source.Where(x => x.EmployeeId == startingId).FirstOrDefault();
        if (result != null) {
            var resultAsE = new [] { result };
            if (!result.ManagerId.HasValue)
                return resultAsE;
            return resultAsE.Union(source.Except(resultAsE).GetTreeForEmployeeNumber(result.ManagerId.Value));
        }
        return new Employee [] { };
    }
}

Upvotes: 2

Ocelot20
Ocelot20

Reputation: 10800

This .AsHierarchy() extension method may be useful: link. However, this only works by providing an easy way to throw your results into linked objects. In order to do that, it'll just get all the records and run its own local recursive query.

If you're looking for a LINQ query that will directly translate to a recursive SQL query via LINQ to SQL, you won't find it. For the best performance, a CTE in a stored procedure is probably what you're looking for. If you have a really simple page that needs to load the whole tree anyway, the AsHierarchy method would probably fit your needs.

Upvotes: 9

automagic
automagic

Reputation: 1077

var managedEmployees = ctx.Employess.Where(x => x.ManagerId = 4).AsEnumerable()

If you want the whole tree at once, the solution is more complex. In SQL its best done with an CTE, I don't know if EF can handle this using linq- more likely an iterative solution would be used.

Upvotes: 0

Doggett
Doggett

Reputation: 3464

You could do something like

    int id = 5;
    do
    {
        employee= employeedata.FirstOrDefault(e => e.EmployeeId == id);

    } while (employee != null && (id = employee.ManagerId) != 0);

but it's a rather dangerous thing to do since it can get stuck in an infinite loop. As far as I know there's no way to make a recursive query directly unless you write a stored procedure.

Upvotes: 0

Related Questions