2014-12-04 20 views
5

Ich möchte Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> aus der Liste der SortingItems dynamisch erstellen. Ich meine, ich möchte den folgenden Ausdruck erstellen:Erstellen von Func <IQueryable <TEntity>, IOrderedQueryable <TEntity>> dynamisch?

entity => entity.OrderBy(c => c.Id).ThenBy(c => c.Name).ThenByDescending(c => c.LastName)

Das folgende ist mein Code:

[DataContract] 
public class SortingItem 
{ 
    [DataMember] 
    public string PropertySelectorString { get; set; } 

    [DataMember] 
    public SortingDirectionsEnum SortingDirections { get; set; } 
} 

[DataContract] 
public enum SortingDirectionsEnum 
{ 
    [EnumMember] 
    Descending = 0, 

    [EnumMember] 
    Ascending = 1 
} 

public Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetSortingFunc<TEntity>() 
{ 
    _entityType = typeof(TEntity); 
    _parameterExpression = Expression.Parameter(_entityType, "entity"); 
    _iQueryableParameterExpression = Expression.Parameter(typeof(IQueryable<TEntity>), "f"); 

    MethodInfo orderByMethodInfo = null; 
    Expression resultExpression = null; 

    foreach (SortingItem sortingItem in SortingItems) 
    { 
     MemberExpression memberExpression = GetLeftSide(sortingItem.PropertySelectorString, _entityType, _parameterExpression); // I'm dead sure about working this line 

     switch (sortingItem.SortingDirections) 
     { 
      case SortingDirectionsEnum.Descending: 
       orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "OrderBy" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type); 
       if (resultExpression != null) 
        orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "ThenBy" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type); 
       break; 

      case SortingDirectionsEnum.Ascending: 
       orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type); 
       if (resultExpression != null) 
        orderByMethodInfo = typeof(Queryable).GetMethods().First(method => method.Name == "ThenByDescending" && method.GetParameters().Length == 2).MakeGenericMethod(_entityType, memberExpression.Type); 
       break; 
     } 

     MethodCallExpression methodCallExpression; 
     if (resultExpression != null) 
      // Exception 
      // An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll 
      // Additional information: Incorrect number of arguments supplied for call to method 'System.Linq.IOrderedQueryable`1[ConsoleApplication1.User] ThenBy[User,Int32](System.Linq.IOrderedQueryable`1[ConsoleApplication1.User], System.Linq.Expressions.Expression`1[System.Func`2[ConsoleApplication1.User,System.Int32]])' 
      methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, resultExpression, Expression.Lambda(memberExpression, _parameterExpression)); 
     else 
      methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, Expression.Lambda(memberExpression, _parameterExpression)); 

     resultExpression = Expression.Lambda(methodCallExpression, _iQueryableParameterExpression); 
    } 

    Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>> lambdaExpression = Expression.Lambda<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>(resultExpression, _parameterExpression); 
    return lambdaExpression.Compile(); 
} 

Es ist OK {f.OrderBy(entity => entity.Id)} oder {f.ThenBy(entity => entity.Name)} separat zu schaffen, aber ich Ausnahme bei der folgenden Zeile

methodCallExpression = Expression.Call(orderByMethodInfo, _iQueryableParameterExpression, resultExpression, Expression.Lambda(memberExpression, _parameterExpression)); 

Wie soll ich Expression.Call kombinieren kombinieren {f.OrderBy(entity => entity.Id)} mit {f.ThenBy(entity => entity.Name)}, ....?

+0

Können Sie erklären, was Sie brauchen das? Möglicherweise gibt es eine viel einfachere Lösung für Ihr "größeres Problem" ... – ChrFin

+0

Ich habe 'SortingItems' in der Client-App erstellt und an den Dienst gesendet. Im Dienst möchte ich die Sortierfunktion 'func' erstellen, die im Entity-Framework verwendet wird –

Antwort

2

Ich empfehle Ihnen, solchen Code nicht zu schreiben, da es schwer zu lesen ist. Ich musste diese Monster in der Vergangenheit pflegen.

Wenn Sie in der Lösung tatsächlich interessiert sind, können Sie DynamicLINQ herunterladen, und dann wird Ihre Anfrage wie:

public string GetSortCriteria(this SortingItem item){ 
    return string.Format("{0} {1}", item.PropertySelectorString, 
      item.SortingDirections == SortingDirectionsEnum.Descending ? 
      "DESC" : "ASC"); 
} 

// later: 
var mergedSortCriteria= string.Join(",", 
    SortingItems.Select(item => item.GetSortCriteria()); 

Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> myFunc = 
     source => source.OrderBy("id " + mergedSortCriteria); 
Verwandte Themen