2016-10-25 2 views
1

Comment puis-je générer dynamiquement une expression order-by en ne connaissant que le nom de la propriété (ou même le nom d'une sous-propriété)?Construction de OrderBy-expression à l'exécution par nom de propriété pouvant être imbriqué

Ce que je suis en train de réaliser est quelque chose comme:

dbResult = // some database-query as IQueryable<TSource> which is not yet executed; 

if (!string.IsNullOrEmpty(request.OrderBy)) { // the user want's to group the results 
    var grouped = dbResult.GroupBy(/* this should be build dynamically */); 
} 

J'ai besoin pour commencer comme GroupBy est en attente d'une Func<TSource, TKey>, mais je ne sais TKey à l'exécution qui peut être une chaîne, int ou même un Guid.

L'utilisateur pourrait passer quelque chose comme "Country.Name" à la propriété request.OrderBy ce qui signifie que les résultats devraient être regroupés par sous-propriété (sous-sélection), le nom d'un pays.

Je pense que ExpressionTrees est la solution, mais je suis coincé avant même de commencer car je ne sais pas comment gérer l'inconnu Type ainsi que l'option de grouper par une propriété d'un sous-select/sous-propriété.

+1

Dupliquer? http://stackoverflow.com/questions/7488391/building-an-orderby-expression-using-the-name-of-a-property?rq=1 –

+0

@IanMercer: Travailler pour les propriétés de la sélection principale, mais pas pour les sous-propriétés, par exemple Country.Name car il lance une exception 'Propriété Instance 'Country.Name' n'est pas définie pour le type 'CountrySelect'' – KingKerosin

+0

Vous devez utiliser' Expression.Property' sur chaque propriété d'une chaîne. Voir http://stackoverflow.com/questions/11439218/how-can--create-a-expression-property-of-a-child-object –

Répondre

0

Voici comment vous pouvez construire dynamiquement une expression/requête GroupBy:

public static class QueryableExtensions 
{ 
    public static IQueryable GroupByMember(this IQueryable source, string memberPath) 
    { 
     var parameter = Expression.Parameter(source.ElementType, "x"); 
     var member = memberPath.Split('.') 
      .Aggregate((Expression)parameter, Expression.PropertyOrField); 
     var selector = Expression.Lambda(member, parameter); 
     var groupByCall = Expression.Call(typeof(Queryable), "GroupBy", 
      new Type[] { parameter.Type, member.Type }, 
      source.Expression, Expression.Quote(selector)); 
     return source.Provider.CreateQuery(groupByCall); 
    } 
} 

Le problème est cependant qu'il n'y a pas de bonne façon générique de représenter le résultat. Et travailler avec non générique IQueryable/IEnumerable n'est pas facile car presque toutes les méthodes LINQ fonctionnent sur des interfaces génériques. Surtout avec IQueryable, vous trouverez que vous avez besoin de créer de plus en plus de méthodes comme celle-ci, donc vous pourriez envisager d'utiliser le paquet Dynamic LINQ.

+0

Btw, je vois que vous utilisez une partie de cette réponse dans votre prochaine question, donc OMI pour l'exactitude, vous devriez avoir accepté celui-ci en premier. –