2009-11-04 3 views
9

Supposons que j'ai deux classes:propriétés imbriquées Access avec lambda dynamique à l'aide Linq.Expression

class person 
{ 
    int ID 
    string name 
    Address address 
} 
class address 
{ 
    int ID 
    string street 
    string country 
} 

Ces classes sont plus ou moins donnés, ils sont mis en correspondance via NHibernate pour être honnête :)

Dans une grille (datatables.net comme base) je voudrais avoir un tri indépendant du type.

Par conséquent, je crée une expression lambda:

var param = Expression.Parameter(typeof(T), typeof(T).Name); 
    var sortExpression = Expression.Lambda<Func<T, object>> 
           (Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param); 

Si je passe personne comme type T et remplacer la « propriété pour trier » avec « nom » il fonctionne très bien (crée un lambda correct). Si la propriété est de trier « address.street » ça ne marchera pas, jetez-moi l'erreur suivante:

Property 'address.street' is not defined for type 'person' 

Je ne vois qu'une seule solution à ce jour, mais pas assez clair ... Je voudrais essayer de diviser la chaîne qui contient le nom de propriété (divisé par.)

Quelqu'un peut-il donner une meilleure solution? J'ai besoin d'ajouter le sortExpression à un objet IQueryable query.OrderBy(sortExpression).

Je ne sais pas si mon titre est clair, veuillez le corriger.

Merci d'avance.

Répondre

2

Il me semble que vous essayez de réécrire Microsoft DynamicQuery. Pourquoi ne pas simplement utiliser cela à la place?

Voici un exemple:

IQueryable<Foo> myQuery = GetHibernateQuery(); 
myQuery = myQuery.OrderBy("address.street"); 
+0

Étant donné que je ne reçois qu'un objet IQueryable contenant déjà un tas de données, j'ajoute la pagination, etc. Ensuite, je ne charge que les données laissées dans la requête. Ceci est fait par nHibernate. Seulement pour le tri, il ne peut pas être la solution (j'espère) – griti

+0

C'est mon point. DynamicQuery peut déjà faire cela "ajouter le tri à une requête existante." J'ai une solution de démonstration sur mon blog qui fait juste cela. http://blogs.teamb.com/craigstuntz/2009/04/27/38243/ –

+0

oh merci, je vais le lire – griti

12

Ce qui est pas clair?

Vous devez diviser puis utiliser:

Expression.Property(Expression.Property(param, "address"), "street") 
+0

Uhm et comment feriez-vous cela si peut-être il arrive quelque chose comme 'person.company.address.street'? Je ne sais pas comment "l'imbriquer" .. ou s'il y a d'autres façons, comme Craig posté ... – griti

+1

Expression.Property (Expression.Property (Expression.Property (Expression.Property (param, "person"), "société"), "adresse"), "rue") La boucle simple fonctionnera. – LukLed

+0

pas à la main? :) – griti

4

est ici une version plus générique de la réponse LukLed:

protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName) 
    { 
     string[] parts = propertyName.Split('.'); 
     int partsL = parts.Length; 

     return (partsL > 1) 
      ? 
      Expression.Property( 
       NestedExpressionProperty(
        expression, 
        parts.Take(partsL - 1) 
         .Aggregate((a, i) => a + "." + i) 
       ), 
       parts[partsL - 1]) 
      : 
      Expression.Property(expression, propertyName); 
    } 

Vous pouvez l'utiliser comme ceci:

var paramExpression = Expression.Parameter(this.type, "val"); 
var firstProp = NestedExpressionProperty(paramExpression,"address.street"); 
+0

C'est une méthode excellente et réutilisable pour résoudre ce problème. Je vous remercie. –

+0

Excellente réponse +1. Vous pouvez le faire dans une ligne: 'return propertyName.Split ('.'). Aggregate (expression, (corps, membre) => Expression.PropertyOrField (corps, membre));'. – nawfal

+0

Si vous n'aimez pas les doublures, peut-être une version plus lisible utilise 'foreach', comme:' Expression body = expression; foreach (var membre de propertyName.Split ('.')) { body = Expression.PropertyOrField (corps, membre); } le corps de retour; ' – nawfal

0

Essayez celui-ci

public static IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder) 
    { 
     if (string.IsNullOrWhiteSpace(fieldName)) return data; 
     if (string.IsNullOrWhiteSpace(sortOrder)) return data; 

     var param = Expression.Parameter(typeof(T), "i"); 

     MemberExpression property = null; 
     string[] fieldNames = fieldName.Split('.'); 
     foreach (string filed in fieldNames) 
     { 
      if (property == null) 
      { 
       property = Expression.Property(param, filed); 
      } 
      else 
      { 
       property = Expression.Property(property, filed); 
      } 
     } 

     Expression conversion = Expression.Convert(property, typeof(object));//Expression.Property(param, fieldName) 
     var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param); 

     return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression) 
      : data.OrderBy(mySortExpression); 
    } 
Questions connexes