How to Convert LINQ Comprehension Query Syntax to Method Syntax using Lambda
Asked Answered
A

4

23

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.

Antinomian answered 3/3, 2013 at 2:52 Comment(0)
V
25

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

Verdun answered 3/3, 2013 at 21:47 Comment(1)
I have LINQpad premium and it a great tool to view Lambda expression. I use for tons of stuff, such as prototyping application and just testig code. Thanks for the webshot; it really helps to get the point across.Antinomian
A
14

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.

Antinomian answered 3/3, 2013 at 2:52 Comment(1)
This will create an expression tree filteredEmployees.ExpressionAntinomian
T
3

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.

Trend answered 3/3, 2013 at 3:47 Comment(0)
W
0

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();
Woolridge answered 1/12, 2022 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.