web-dev-qa-db-fra.com

Multiple "commander par" dans LINQ

J'ai deux tables, movies et categories, et je reçois une liste ordonnée par categoryID d'abord, puis par nom.

La table de film a trois colonnes ID, Nom et CategoryID. La table des catégories a deux colonnes ID et Nom.

J'ai essayé quelque chose comme ce qui suit, mais cela n'a pas fonctionné.

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

Cela devrait fonctionner pour vous:

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

En utilisant LINQ, syntaxe de requête non-lambda, vous pouvez procéder comme suit:

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

[EDIT to address comment] Pour contrôler l'ordre de tri, utilisez les mots-clés ascending (qui est la valeur par défaut et n'est donc pas particulièrement utile) ou descending, comme suit:

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

Ajouter un nouveau":

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

Cela fonctionne sur ma boîte. Il retourne quelque chose qui peut être utilisé pour trier. Il retourne un objet avec deux valeurs.

Semblable mais différent du tri par colonne combinée, comme suit.

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

utilisez la ligne suivante de votre DataContext pour consigner l'activité SQL sur le DataContext sur la console. Vous pourrez alors voir exactement ce que vos instructions linq demandent à la base de données:

_db.Log = Console.Out

Les déclarations LINQ suivantes:

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

ET

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

produire le code SQL suivant:

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

Considérant que, en répétant OrderBy dans Linq, il semble que la sortie SQL résultante soit inversée:

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

ET

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

produire le code SQL suivant (Name et CategoryId sont commutés):

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

J'ai créé des méthodes d'extension (ci-dessous) pour que vous n'ayez pas à vous inquiéter si un IQueryable est déjà commandé ou non. Si vous souhaitez commander par plusieurs propriétés, procédez comme suit:

// 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);

Ceci est particulièrement utile si vous créez la commande de manière dynamique, par exemple à partir d'une liste de propriétés à trier.

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);
        }
    }
}
20
sjkm

Il existe au moins une autre façon de faire cela en utilisant LINQ, bien que ce ne soit pas la plus simple. Vous pouvez le faire en utilisant la méthode OrberBy() qui utilise un IComparer. Vous devez d’abord implémenter une IComparer pour la classe Movie comme ceci:

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);
        }
    }
}

Ensuite, vous pouvez commander les films avec la syntaxe suivante:

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

Si vous avez besoin de changer l'ordre dans l'ordre décroissant pour l'un des éléments, il suffit de changer le x et le y à l'intérieur de la méthode Compare() du MovieComparer en conséquence.

15
prudentcoder

Si vous utilisez un référentiel générique

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

else

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