Mike Barlow - BarDev
Mike Barlow - BarDev

Reputation: 11267

How to Convert LINQ Comprehension Query Syntax to Method Syntax using Lambda

Is there a tool, process or a solution that will convert the following LINQ Query Syntax to Method Syntax with Lambdas (dot notation)? I would expect the solution to convert the following Query Syntax to a Method Syntax such as this.

var filteredEmployees = 
    from employee in allEmployees
    where employee.DepartmentID < 4 && employee.EmployeeID < 10
    orderby employee.DepartmentID descending,
            employee.LastName descending
    select employee;

To the following

var filteredEmployees2 = allEmployees.Where(employee => ((employee.DepartmentID < 4) && (employee.EmployeeID < 10)))
        .OrderByDescending(employee => employee.DepartmentID)
        .ThenByDescending(employee => employee.LastName);

I'm would like to use this to learn Method Syntax better.

Upvotes: 23

Views: 15789

Answers (4)

mjacob
mjacob

Reputation: 1

The easiest way to do it, that I have found, is to use Visual Studio built in Action feature:

screenshot

It transforms this:

from numberA in numbersA
                from numberB in numbersB
                where numberA < numberB
                select (numberA, numberB)).ToList();

to this:

numbersA.SelectMany(numberA => numbersB, (numberA, numberB) => new { numberA, numberB })
                .Where(t => t.numberA < t.numberB)
                .Select(t => (t.numberA, t.numberB)).ToList();

Upvotes: 0

Jeff Mercado
Jeff Mercado

Reputation: 134871

You can get a more direct expression by declaring a lambda expression which generates some object. The actual expression will be the query you want to see using the query syntax. Then by inspecting the expression tree generated by the compiler, you can see what method calls are made without having to alter the original query.

Expression<Func<object>> fn = () =>
    from employee in allEmployees
    where employee.DepartmentID < 4 && employee.EmployeeID < 10
    orderby employee.DepartmentID descending,
            employee.LastName descending
    select employee;
// inspect fn.Body

Using IQueryable<> as you did there does not generate the same query but slightly modified. The AsQueryable() call you have to ignore. There's also the possibility that the query provider can rewrite the expression so what you get back using ToString() may not have a 1:1 correspondence. The compiler generated expression will be exactly what you would expect.

Upvotes: 3

Rui Jarimba
Rui Jarimba

Reputation: 17994

LINQPad is a good tool for what you need. I "stole" the following screenshot from their website to better illustrate how it works. If you write a query using linq syntax you can click on the button highlighted in red to see the equivalent lambda syntax:enter image description here

Upvotes: 25

Mike Barlow - BarDev
Mike Barlow - BarDev

Reputation: 11267

If we force the Query Syntax to return a type of IQueryable then we can get to the Method Syntax.

Here I changed the query to return type of IQueryable:

IQueryable<Employee> filteredEmployees = 
    (from employee in allEmployees.AsQueryable()
    where employee.DepartmentID < 4 && employee.EmployeeID < 10
    orderby employee.DepartmentID descending,
            employee.LastName descending
    select employee);

Console.WriteLine(filteredEmployees.ToString());

In the previous code we added "AsQueryable() to the "allEmployees" list type. The return type will now be IQueryable, so "filteredEmployees" will now be of type "IQueryable". Then on the "filteredEmployees" all we need to do is call "ToString()" method.

And the following is written to the console.

System.Collections.Generic.List`1[UserQuery+Employee]
     .Where(employee => ((employee.DepartmentID < 4) AndAlso (employee.EmployeeID < 10)))
     .OrderByDescending(employee => employee.DepartmentID)
     .ThenByDescending(employee => employee.LastName)

It's not perfect, but we can easily edit this to the following

IEnumerable<Employee> filteredEmployees2 = allEmployees
        .Where(employee => ((employee.DepartmentID < 4) && (employee.EmployeeID < 10)))
        .OrderByDescending(employee => employee.DepartmentID)
        .ThenByDescending(employee => employee.LastName);

Console.WriteLine(filteredEmployees);

In the previous code I removed "System.Collections.Generic.List`1[UserQuery+Employee]" and replaced it with "allEmployees". I also replace "AndAlso" with "&&".

This will return the same results as the query in the Query Syntax.

Upvotes: 14

Related Questions