2011-05-24 17 views
2

Je joue autour et essayer de faire une méthode d'extension pour IQueryable qu'elle trie par une propriété arbitraire d'un objet.Réflexion avec IQueryable

public static class IQueryableExtender 

{ 

public static IQueryable<TSource> Sort<TSource>(this IQueryable<TSource> query, string orderProperty, string sortDirection = "asc")  
{ 

    var elementType = query.ElementType; 

    var propertyInfo = elementType.GetProperty(orderProperty); 
    if (propertyInfo == null) 
    { 
     throw new ArgumentException(string.Format("{0} is not a property on {1}", orderProperty, elementType.Name)); 
    } 


    switch (sortDirection.ToLower()) 
    { 
     case "asc": 
     case "ascending": 
      return query.OrderBy(x => propertyInfo.GetValue(x, null)); 
      break; 
     case "desc": 
     case "descending": 
      return query.OrderByDescending(x => propertyInfo.GetValue(x, null)); 
      break; 
    } 

    return query; 
} 
} 

Je reçois cette erreur lorsque j'appelle la méthode. Je suppose que cela a à voir avec le IQueryable n'a pas encore exécuté et récupéré des objets.

LINQ to Entities ne reconnaît pas la méthode System.Object GetValue(System.Object, System.Object[]), et cette méthode ne peut pas être traduit en une expression de magasin.

Je peux le résoudre en exécutant ToList sur le IQueryable mais je récupère les données dans la méthode d'extension et ce n'est pas ce que je veux.

Est-ce que cela peut être résolu?

Répondre

2

LINQ to Entities essaie d'exécuter vos requêtes dans la base de données lorsque vous effectuez une opération LINQ sur un IQueryable <>. Dans votre case "asc", vous faites query.OrderBy, que LINQ to Entities interprète comme "transformer ceci en SQL", et cela échoue puisque vous utilisez des appels de réflexion, qu'il ne sait pas comment convertir en SQL.

OrderBy (...) Vous pouvez faire query.AsEnumerable().. Un effet de ceci est que lorsque l'opération OrderBy commence à s'exécuter, le reste de la requête s'exécutera afin que les données soient fournies. Plutôt que d'utiliser ces astuces de réflexion, vous pouvez utiliser simplement les méthodes OrderBy et OrderByDescending, conçues pour amener un délégué à extraire la valeur de tri. (items.OrderBy(item => item.Property)). Ce qui vous manque est la possibilité de spécifier ascendant ou descendant dans la même méthode, mais je voudrais simplement faire une paire de méthodes comme:

public static IOrderedQueryable<TSource> OrderByAscDesc<TSource, TKey>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, TKey>> keySelector, bool isAsc 
) { 
    return (isAsc ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector); 
} 

public static IOrderedQueryable<TSource> OrderByAscDesc<TSource, TKey>(
    this IQueryable<TSource> source, 
    Func<TSource, TKey> keySelector, bool ascDesc 
) { 
    return (isDesc ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector); 
} 
+0

Merci pour la réponse. Ce n'est pas tout à fait ce que je cherche. J'ai laissé de côté le fait que je travaille avec MVC et que je reçois le nom de la propriété à trier par rapport à la vue. Donc je voulais une méthode où je pourrais juste prendre le paramètre et refléter la valeur de la propriété de l'objet et trier dessus. Ce qui signifierait que je n'ai besoin d'aucune instruction if pour choisir quelle propriété utiliser avec if. – Lejdholt

+0

Cela fait un peu plus de sens. Ajouter AsEnumerable() avant d'utiliser OrderBy devrait le réparer. – Jesper

+0

Je vais essayer. Merci – Lejdholt