2014-12-04 23 views
5

Tôi muốn tạo Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> từ danh sách các SortingItems động. tôi có nghĩa là tôi muốn tạo ra các biểu thức sau đây:Tạo Func <IQueryable <TEntity>, IOrderedQueryable <TEntity>> động?

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

Sau đây là mã của tôi:

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

Đó là OK để tạo {f.OrderBy(entity => entity.Id)} hoặc {f.ThenBy(entity => entity.Name)} riêng rẽ, nhưng tôi nhận được ngoại lệ ở dòng sau

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

Tôi nên sử dụng Expression.Call để kết hợp như thế nào {f.OrderBy(entity => entity.Id)} với {f.ThenBy(entity => entity.Name)}, ....?

+0

bạn có thể giải thích những gì bạn cần là gì? Có thể có một giải pháp dễ dàng hơn cho "vấn đề lớn hơn" của bạn ... – ChrFin

+0

Tôi đã tạo 'SortingItems' trong ứng dụng khách và gửi nó đến dịch vụ. Trong Service tôi muốn tạo phân loại 'func' để sử dụng trong khung thực thể –

Trả lời

2

tôi đề nghị bạn không viết mã như vậy, vì nó là khó đọc. Tôi đã phải duy trì những con quái vật đó trong quá khứ.

Nếu bạn thực sự quan tâm đến các giải pháp, bạn có thể tải DynamicLINQ, và sau đó truy vấn của bạn sẽ được như:

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); 
Các vấn đề liên quan