2014-12-04 24 views
5

SortingItems listesinden Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> dinamik olarak oluşturmak istiyorum. entity => entity.OrderBy(c => c.Id).ThenBy(c => c.Name).ThenByDescending(c => c.LastName)Func oluşturma <IQueryable <TEntity>, IOrderedQueryable <TEntity>> dinamik olarak?

aşağıdaki

benim kodudur: Yani aşağıdaki ifade oluşturmak istiyorum

[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(); 
} 

O {f.OrderBy(entity => entity.Id)} veya {f.ThenBy(entity => entity.Name)} ayrı oluşturmak için Tamam, ama şu satırda

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

Expression.Call'u birleştirmek için nasıl kullanmalıyım {f.ThenBy(entity => entity.Name)} ile {f.OrderBy(entity => entity.Id)}, ....? Okunması zor olduğu için böyle bir kod yazmamanızı öneririm

+0

sizin için o gerekenleri açıklar mısınız? Muhtemelen "büyük sorun" için çok daha kolay bir çözüm var ... – ChrFin

+0

İstemci uygulamasında 'SortingItems'i oluşturdum ve servise gönderdim. Hizmette Ben varlık çerçevesinde kullanmak için 'func' sıralama oluşturmak istiyorum –

cevap

2

. Bu canavarları geçmişte tutmalıydım. Eğer çözümde aslında ilgileniyorsanız

, sen DynamicLINQ indirebilir ve daha sonra sorgu gibi olacaktır:

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); 
İlgili konular