Multiple "order by" in LINQ

LinqSql Order-By

Linq Problem Overview


I have two tables, movies and categories, and I want to get an ordered list by categoryID first and then by Name.

The movie table has three columns ID, Name and CategoryID. The category table has two columns ID and Name.

I tried something like the following, but it didn't work.

var movies = _db.Movies.OrderBy( m => { m.CategoryID, m.Name })

Linq Solutions


Solution 1 - Linq

This should work for you:

var movies = _db.Movies.OrderBy(c => c.Category).ThenBy(n => n.Name)

Solution 2 - Linq

Using non-lambda, query-syntax LINQ, you can do this:

var movies = from row in _db.Movies 
             orderby row.Category, row.Name
             select row;

[EDIT to address comment] To control the sort order, use the keywords ascending (which is the default and therefore not particularly useful) or descending, like so:

var movies = from row in _db.Movies 
             orderby row.Category descending, row.Name
             select row;

Solution 3 - Linq

Add "new":

var movies = _db.Movies.OrderBy( m => new { m.CategoryID, m.Name })

That works on my box. It does return something that can be used to sort. It returns an object with two values.

Similar, but different to sorting by a combined column, as follows.

var movies = _db.Movies.OrderBy( m => (m.CategoryID.ToString() + m.Name))

Solution 4 - Linq

use the following line on your DataContext to log the SQL activity on the DataContext to the console - then you can see exactly what your linq statements are requesting from the database:

_db.Log = Console.Out

The following LINQ statements:

var movies = from row in _db.Movies 
             orderby row.CategoryID, row.Name
             select row;

AND

var movies = _db.Movies.OrderBy(m => m.CategoryID).ThenBy(m => m.Name);

produce the following SQL:

SELECT [t0].ID, [t0].[Name], [t0].CategoryID
FROM [dbo].[Movies] as [t0]
ORDER BY [t0].CategoryID, [t0].[Name]

Whereas, repeating an OrderBy in Linq, appears to reverse the resulting SQL output:

var movies = from row in _db.Movies 
             orderby row.CategoryID
             orderby row.Name
             select row;

AND

var movies = _db.Movies.OrderBy(m => m.CategoryID).OrderBy(m => m.Name);

produce the following SQL (Name and CategoryId are switched):

SELECT [t0].ID, [t0].[Name], [t0].CategoryID
FROM [dbo].[Movies] as [t0]
ORDER BY [t0].[Name], [t0].CategoryID

Solution 5 - Linq

I have created some extension methods (below) so you don't have to worry if an IQueryable is already ordered or not. If you want to order by multiple properties just do it as follows:

// We do not have to care if the queryable is already sorted or not. 
// The order of the Smart* calls defines the order priority
queryable.SmartOrderBy(i => i.Property1).SmartOrderByDescending(i => i.Property2);

This is especially helpful if you create the ordering dynamically, f.e. from a list of properties to sort.

public static class IQueryableExtension
{
	public static bool IsOrdered<T>(this IQueryable<T> queryable) {
		if(queryable == null) {
			throw new ArgumentNullException("queryable");
		}

		return queryable.Expression.Type == typeof(IOrderedQueryable<T>);
	}

	public static IQueryable<T> SmartOrderBy<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> keySelector) {
		if(queryable.IsOrdered()) {
			var orderedQuery = queryable as IOrderedQueryable<T>;
			return orderedQuery.ThenBy(keySelector);
		} else {
			return queryable.OrderBy(keySelector);
		}
	}

	public static IQueryable<T> SmartOrderByDescending<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> keySelector) {
		if(queryable.IsOrdered()) {
			var orderedQuery = queryable as IOrderedQueryable<T>;
			return orderedQuery.ThenByDescending(keySelector);
		} else {
			return queryable.OrderByDescending(keySelector);
		}
	}
}

Solution 6 - Linq

There is at least one more way to do this using LINQ, although not the easiest. You can do it by using the OrberBy() method that uses an IComparer. First you need to implement an IComparer for the Movie class like this:

public class MovieComparer : IComparer<Movie>
{
    public int Compare(Movie x, Movie y)
    {
        if (x.CategoryId == y.CategoryId)
        {
            return x.Name.CompareTo(y.Name);
        }
        else
        {
            return x.CategoryId.CompareTo(y.CategoryId);
        }
    }
}

Then you can order the movies with the following syntax:

var movies = _db.Movies.OrderBy(item => item, new MovieComparer());

If you need to switch the ordering to descending for one of the items just switch the x and y inside the Compare() method of the MovieComparer accordingly.

Solution 7 - Linq

If use generic repository

> lstModule = _ModuleRepository.GetAll().OrderBy(x => new { x.Level,
> x.Rank}).ToList();

else

> _db.Module.Where(x=> ......).OrderBy(x => new { x.Level, x.Rank}).ToList();

       

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSashaView Question on Stackoverflow
Solution 1 - LinqNathan WView Answer on Stackoverflow
Solution 2 - LinqScott StaffordView Answer on Stackoverflow
Solution 3 - LinqAlexView Answer on Stackoverflow
Solution 4 - LinqOliver SlayView Answer on Stackoverflow
Solution 5 - LinqsjkmView Answer on Stackoverflow
Solution 6 - LinqprudentcoderView Answer on Stackoverflow
Solution 7 - LinqSaint-martin GuillaumeView Answer on Stackoverflow