2013-04-15 4 views
6

J'utilise les modèles mentionnés ici http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-applicationdynamique Func <IQueryable <TEntity>, IOrderedQueryable <TEntity>> Expression

et je suis en utilisant la méthode ci-dessous pour interroger EF

public virtual IEnumerable<TEntity> Get(
     Expression<Func<TEntity, bool>> filter = null, 
     Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, 
     string includeProperties = "") 
    { 
     IQueryable<TEntity> query = dbSet; 

     if (filter != null) 
     { 
      query = query.Where(filter); 
     } 

     foreach (var includeProperty in includeProperties.Split 
      (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) 
     { 
      query = query.Include(includeProperty); 
     } 

     if (orderBy != null) 
     { 
      return orderBy(query).ToList(); 
     } 
     else 
     { 
      return query.ToList(); 
     } 
    } 

Maintenant, je veux créer l'expression Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> dynamique commander mes données.

Je ne connais que le nom du champ en tant que chaîne et le type ordre (ascendant, descendant) sous forme de chaîne (asc, desc)

+0

Ce n'est pas la forme habituelle d'un ordre par; avez-vous vu cette? http://stackoverflow.com/questions/41244/dynamic-linq-orderby –

+0

@MarcGravell merci, j'ai vu ça. Mais le tutoriel de MS contient ce code, donc j'essaie d'écrire un LINQ dynamique pour cela. En fait, je pense que j'ai réussi, mais je dois faire quelques tests et ensuite vous faire savoir. –

Répondre

9

Enfin, je pourrais écrire la méthode que je veux.

public static Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetOrderBy(string orderColumn, string orderType) { 
      Type typeQueryable = typeof(IQueryable<TEntity>); 
      ParameterExpression argQueryable = Expression.Parameter(typeQueryable, "p"); 
      var outerExpression = Expression.Lambda(argQueryable, argQueryable); 
      string[] props = orderColumn.Split('.'); 
      IQueryable<TEntity> query = new List<TEntity>().AsQueryable<TEntity>(); 
      Type type = typeof(TEntity); 
      ParameterExpression arg = Expression.Parameter(type, "x"); 

      Expression expr = arg; 
      foreach(string prop in props) { 
       PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 
       expr = Expression.Property(expr, pi); 
       type = pi.PropertyType; 
      } 
      LambdaExpression lambda = Expression.Lambda(expr, arg); 
      string methodName = orderType == "asc" ? "OrderBy" : "OrderByDescending"; 

      MethodCallExpression resultExp = 
       Expression.Call(typeof(Queryable), methodName, new Type[] { typeof(TEntity), type }, outerExpression.Body, Expression.Quote(lambda)); 
      var finalLambda = Expression.Lambda(resultExp, argQueryable); 
      return (Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)finalLambda.Compile(); 
     } 

Cette méthode prend deux paramètres, d'abord un nom de champ, l'autre est asc ou desc. Le résultat de la méthode peut être utilisé directement avec l'objet IQueryable.

Merci pour votre aide

2

Je ne sais pas exactement ce que vous voulez accomplir, mais j'avais changé votre code et ajouter un peu exemple pour démontrer comment ça marche.

Ceci est une application de console simple, qui a dummyText comme liste. La méthode interrogeable permet d'utiliser l'expression de filtrage et de tri comme vous le souhaitez. J'espère que cela aide

class Program 
{ 

    private List<string> _dummyText = new List<string>(){ "Arda", 
     "Araba", 
     "Antartika", 
     "Balon"}; 

    static void Main(string[] args) 
    { 
     Program p = new Program(); 
     List<string> result = p.Get(s => s.StartsWith("A"), orderBy: q => q.OrderBy(d => d.Length)).ToList(); 

     Console.ReadLine(); 
    } 


    public virtual IEnumerable<string> Get(
    Expression<Func<string, bool>> filter = null, 
    Func<IQueryable<string>, IOrderedQueryable<string>> orderBy = null) 
    { 

     IQueryable<string> query = _dummyText.AsQueryable(); 

     if (filter != null) 
     { 
      query = query.Where(filter); 
     } 

     if (orderBy != null) 
     { 
      return orderBy(query).ToList(); 
     } 
     else 
     { 
      return query.ToList(); 
     } 



    } 

} 
+0

merci pour la réponse, mais je pense qu'il y a un peu mal compris. Je dois envoyer z => z.OrderBy (x => x.CreatedDate) au paramètre orderBy. Donc, votre réponse ne fonctionnera pas à mon avis. –

+0

Vous pouvez utiliser certains paramètres externes pour l'expression linq afin d'avoir une exécution conditionnelle de la méthode en ligne si ... Ex: string direct = "DESC"; Liste résultat = p.Obtenez (s => s.StartsAvec ("A"), orderBy: q => ((direct == "ASC")? Q.OrderBy (d => d.Length): q. OrderByDescending (d => d.Length))). ToList(); Mais je suppose que ce n'est pas exactement ce que vous voulez ... – Arda

1

Ceci est très en retard à la fête, mais la bonne réponse se trouve sur une autre question à https://stackoverflow.com/a/10935223/14275

var students = repository.Get(x => x.FirstName = "Bob",q => q.OrderBy(s => s.LastName)); 
Questions connexes