3

Let's say I have the following simplified Linq query which will be run against the database using LinqToSQL:

public IEnumerable<MembershipDto> GetAllUserMemberships()
{
    return (from m in _workspace.GetDataSource<UserMembership>()
            join g in _workspace.GetDataSource<Group>()
                on m.GroupID equals g.GroupID
            join u in _workspace.GetDataSource<User>()
                on m.UserID equals u.UserID
            select 
                new MembershipDto
                {
                    GroupID = g.GroupID,
                    GroupName = g.Name,
                    UserID = u.UserID,
                    UserName = u.Name
                }
            ).Distinct()
             .OrderBy(x => x.GroupName)
             .ThenBy(x => x.UserName);
}

For performance sake I want as much of this query as possible to be run inside the generated SQL query; however I want the maintain the business logic in Linq so it can be easily unit tested.

The issue I have is that I am uncertain where the above query stops being executed in SQL and starts being operated on in memory.

My assumption is that as soon as the data is being selected into the new MembershipDto it is no longer being conducted in SQL; therefore the subsequent OrderBy() ThenBy() and Distinct() operations occur in memory.

However the OrderBy() produces a collection of type IOrderedQueryable rather than an IOrderedEnumerable; which indicates to me that the query may still be executed in its entirety in SQL.

Is my assumption correct, or is the whole query converted into SQL and if so why is this the case?

7
  • 1
    Have you tried running a profiler to examine that executed SQL? It should give a good indication of how much is being performed in SQL.
    – NibblyPig
    Commented Jun 13, 2013 at 16:25
  • "I want the maintain the business logic in Linq so it can be easily unit tested" 1) Whether Linq executes it on your client app or in SQL, your logic is still in Linq, so, 2) neither choice by Linq should have any effect on your unit testing. Commented Jun 13, 2013 at 16:35
  • 1
    Until you iterate or something causes an iteration, it's still constructing a SQL statement. You should be fine here Commented Jun 13, 2013 at 16:43
  • @DarrenKopp, does the function return type IEnumerable<T> mean that is the point it exits the domain of L2S and enters the domain of L2O? I think it does because Linq to Sql queries return IQueryable<T>. Commented Jun 13, 2013 at 16:49
  • 1
    Yes, once you hit IEnumerable you are in linq 2 objects, which means that everything will be done in memory, but only once you start iterating. Commented Jun 13, 2013 at 16:54

2 Answers 2

3

Just look at the generated SQL. I'm fairly confident that your italicized assumption is wrong. The LINQ to SQL provider will recognize that your OrderBy, ThenBy and Distinct operations are executed exclusively on SQL results so it completes those on the rows you select before deserializing them into objects. That part of the query would only executed by LINQ to Objects if you tried to operate on values that aren't available to the database at execution time.

If in your initializer you set some property to a value that wasn't available in the query results then used that in the OrderBy clause it would certainly do the ordering in memory because there would be no other way. In this case, your select is translated into a SQL SELECT, then OrderBy and Distinct are called as they normally would be. Converting your selection to an object is an operation that is completely independent from selecting columns in the database. To the SQL provider your query is no different than a simple select statement, it builds an expression tree and converts whatever it can into SQL at execution time.

1
  • Thank you @evanmcdonnal; I used an integration test to get hold of the generated SQL Query and it does indeed perform all the ordering and the distinct operation in SQL. Commented Jun 14, 2013 at 8:20
1

I believe all of the code you posted will be converted into sql. The MembershipDto() construction will map to a select statement.

You will "exit" Linq to Sql and "enter" Linq to Objects when your function casts to IEnumerable and the enumerator is executed.

If you're developing in Linq to Sql its absolutely essential that you have the tools to test this for yourself.

I recommend LINQPad. You code in C# and it will show you the generated SQL.

Another solution is to log the generated SQL within your Data Context:

#if DEBUG
        /// <summary>
        /// Code which runs when the data context is created; called from the constructor
        /// </summary>
        /// <remarks>Adds console and/or ASP.NET trace logger in DEBUG builds only</remarks>
        partial void OnCreated()
        {
            this.DebugBuildLogging();
        }
#endif

I would also recommend reading a good book on LINQ. You will be rewarded many times over.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.