views:

579

answers:

3

I'm using the following query syntax

from table where where orderby orderby

Where the first orderby is a date and second orderby is a date. I would assume this would work like orderby thenby but appears to be doing something else.

1 How can I do an orderby thenby using the above syntax without using extension syntax. (Got it)

2 And what does the orderby, orderby do?

A: 

The answer to the thenby should be like this

orderby 1, 2

I'll leave part #2 for someone else.

Curtis White
+1  A: 

How can I do an orderby thenby using the above syntax without using extension syntax.

Use a comma between the fields:

orderby a, b

And what does the orderby, orderby do?

When you use orderby twice in a row the elements conceptually will first be sorted using the first orderby, and then sorted again using the second orderby. Because the sorting is defined to be a stable sort (objects which are tied with the second orderby will remain in the same order as after sorting with the first orderby it effectively means that this:

var query = from x in l
            orderby x.A
            orderby x.B
            select x;

is equivalent to:

var query = from x in l
            orderby x.B, x.A
            select x;

The result is that the orderby terms are swapped from what you probably intended.

Testing it with LINQ to SQL

This can be verified by trying it in LINQ to SQL. I created the following query:

var query = from a in dc.Orders
            orderby a.Date
            orderby a.CustomerID
            select a;

and this was the generated SQL:

SELECT [t0].[ID], [t0].[CustomerID], [t0].[Date], [t0].[Description]
FROM [dbo].[Order] AS [t0]
ORDER BY [t0].[CustomerID], [t0].[Date]

Note that the orderby a.Date is not ignored. Both terms are included in the ORDER BY clause, but in the opposite order than you might have intended.

Mark Byers
Per specification, OrderBy is always a stable sort (regardless of LINQ provider.) What that means is "if the keys of two elements are equal, the order of the elements is preserved." Whether or not chained OrderBy's will preserve ordering depends on the keys being used, not on the LINQ provider (though that will obviously affect the key values).
hemp
@hemp: After reasearching it more, I think you are right. Strangely though your own answer where you quote from MSDN (`Doing this introduces a new primary ordering that ignores the previously established ordering.`) contradicts what you just said in this comment. But I think its MSDN that is wrong.
Mark Byers
@Mark Byers: It doesn't directly contradict, it's just confusing. What it's saying is that the existing order won't be taken into account by the new primary ordering. **However**, once it applies the initial ordering, if the new ordering finds key values to be equal, it will not reorder those items. So in fact both statements are true, just not very clear.
hemp
@hemp: OK I think I understand it now. I have to agree with you that it is confusing. :) I have tested it with both LINQ to Objects and LINQ to SQL and the sorting is stable in both cases. I have to say I was a little surprised that the SQL was exactly as it should be - a single ORDER BY with the terms reversed. Someone has done a good job there!
Mark Byers
+2  A: 

Performing a ThenBy in Query Expression Syntax is straighforward, simply follow the initial orderby with a comma and a 2nd statement:

// Create the data source.
List<Student> students = GetStudents();

// Create the query.
IEnumerable<Student> sortedStudents =
    from student in students
    orderby student.Last ascending, student.First ascending
    select student;

Applying a 2nd orderby using the standard query operators (extension methods) will actually apply the second orderby to the result of the query result which includes the first orderby. In effect, only the second orderby will apply, although you'll still spend CPU time calculating the first order.

This is actually answered directly in the MSDN documentation for the Enumerable.OrderBy and Enumerable.ThenBy methods.

Because IOrderedEnumerable inherits from IEnumerable, you can call OrderBy or OrderByDescending on the results of a call to OrderBy, OrderByDescending, ThenBy or ThenByDescending. Doing this introduces a new primary ordering that ignores the previously established ordering.

hemp