2011-09-01 9 views
57

पैरामीटर के रूप में लेने वाले मान का उपयोग करके orderby पर दिए गए तर्क को मैं कैसे निर्दिष्ट करूं?मैं लिंक ऑर्डरबी तर्क को गतिशील रूप से कैसे निर्दिष्ट करूं?

पूर्व:

List<Student> existingStudends = new List<Student>{ new Student {...}, new Student {...}} 

वर्तमान कार्यान्वयन:

List<Student> orderbyAddress = existingStudends.OrderBy(c => c.Address).ToList(); 

c.Address के बजाय, मैं कैसे ले जा सकते हैं कि एक पैरामीटर के रूप?

उदाहरण

string param = "City"; 
List<Student> orderbyAddress = existingStudends.OrderByDescending(c => param).ToList(); 
+2

आप हो सकता है डायनामिक लिंक की तलाश में: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx – BrokenGlass

+0

@Nev_Rahd: सवाल को थोड़ा सा स्पष्ट करने का प्रयास किया। साथ ही, 'ऑर्डरबी' एक लिंक सुविधा है, और 'आईएनमेर्यूरेबल' पर है, न कि 'सूची' के लिए विशिष्ट सुविधा। संपादन को वापस रोल करने या इसे और बदलने के लिए स्वतंत्र महसूस करें :) –

+0

संभावित डुप्लिकेट [डायनेमिक LINQ ऑर्डरबी पर IENumerable ] (http: // stackoverflow।कॉम/प्रश्न/41244/गतिशील-linq-orderby-on-ienumerablet) –

उत्तर

92

यहाँ प्रतिबिंब का उपयोग कर एक possiblity है ऐसा करने में सक्षम होना चाहिए ...

var param = "Address";  
var propertyInfo = typeof(Student).GetProperty(param);  
var orderByAddress = items.OrderBy(x => propertyInfo.GetValue(x, null)); 
+0

यही वह है जिसे मैं ढूंढ रहा था। मेरे मूल उत्तर से .GetValue भाग गुम था। – tsells

+0

यह एक awsm कोड है ... धन्यवाद, इससे मुझे बहुत मदद मिली। – Harsha

+2

लेकिन क्या यह सच है जब प्रदाता द्वारा व्याख्या किए गए लिंक अभिव्यक्तियों की बात आती है, जैसे एंटीटी फ्रेमवर्क (एसक्यूएल सर्वर, या अन्य) ?? –

1

यह आपको एक string गुजरती हैं, के रूप में आप अपने प्रश्न में के लिए कहा नहीं करता है, लेकिन यह अभी भी आप के लिए काम कर सकते हैं।

OrderByDescending विधि एक Func<TSource, TKey> लेता है, तो आप अपने समारोह इस तरह से फिर से लिखने कर सकते हैं:

List<Student> QueryStudents<TKey>(Func<Student, TKey> orderBy) 
{ 
    return existingStudents.OrderByDescending(orderBy).ToList(); 
} 

OrderByDescending के लिए अन्य भार के हैं और साथ ही है कि एक Expression<Func<TSource, TKey>> लेते हैं, और/या एक IComparer<TKey>। आप उन लोगों को भी देख सकते हैं और देख सकते हैं कि वे आपको कुछ उपयोग प्रदान करते हैं या नहीं।

+0

यह काम नहीं करता है क्योंकि आप टीकेई के प्रकार को परिभाषित नहीं करते हैं। इसके बजाय आपको रखने के लिए अपना बदलना होगा। –

+0

@PatrickDesjardins - यह बेहतर है? –

+0

यह सिर्फ मेरे लिए काम किया था! मैं एक ऐसा फ़ंक्शन चाहता था जो पास किए गए बूल मान के आधार पर आरोही या अवरोही की सूची का आदेश दे। आपका कोड थोड़ा tweaking के साथ महान काम किया! कार्रवाई में –

67

आप इस प्रकार अभिव्यक्ति पेड़ के निर्माण के लिए प्रतिबिंब का एक छोटा सा उपयोग कर सकते हैं (यह एक विस्तार विधि है):

public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, 
          bool desc) 
{ 
    string command = desc ? "OrderByDescending" : "OrderBy"; 
    var type = typeof(TEntity); 
    var property = type.GetProperty(orderByProperty); 
    var parameter = Expression.Parameter(type, "p"); 
    var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
    var orderByExpression = Expression.Lambda(propertyAccess, parameter); 
    var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType }, 
            source.Expression, Expression.Quote(orderByExpression)); 
    return source.Provider.CreateQuery<TEntity>(resultExpression); 
} 

orderByProperty गुण नाम आप से और अगर ऑर्डर करने के लिए चाहते है पास पैरामीटर के रूप में सच desc के लिए, अवरोही क्रम में क्रमबद्ध करेगा; अन्यथा, आरोही क्रम में क्रमबद्ध होगा।

अब आप existingStudents.OrderBy("City",true); या existingStudents.OrderBy("City",false);

+6

यह उत्तर शानदार है, और प्रतिबिंब उत्तर से काफी बेहतर है। यह वास्तव में इकाई ढांचे जैसे अन्य प्रदाताओं के साथ काम करता है। – Sam

+0

यह बहुत अच्छा है। धन्यवाद। – Saragis

+1

अगर मैं कर सकता तो मैं दस बार वोट दूंगा !!! आप इस तरह विस्तार विधि लिखना सीखते हैं ?? !! – Jach

4
private Func<T, object> GetOrderByExpression<T>(string sortColumn) 
    { 
     Func<T, object> orderByExpr = null; 
     if (!String.IsNullOrEmpty(sortColumn)) 
     { 
      Type sponsorResultType = typeof(T); 

      if (sponsorResultType.GetProperties().Any(prop => prop.Name == sortColumn)) 
      { 
       System.Reflection.PropertyInfo pinfo = sponsorResultType.GetProperty(sortColumn); 
       orderByExpr = (data => pinfo.GetValue(data, null)); 
      } 
     } 
     return orderByExpr; 
    } 

    public List<T> OrderByDir<T>(IEnumerable<T> source, string dir, Func<T, object> OrderByColumn) 
    { 
     return dir.ToUpper() == "ASC" ? source.OrderBy(OrderByColumn).ToList() : source.OrderByDescending(OrderByColumn).ToList();`` 
    } 

// Call the code like below 
     var orderByExpression= GetOrderByExpression<SearchResultsType>(sort); 

    var data = OrderByDir<SponsorSearchResults>(resultRecords, SortDirectionString, orderByExpression);  
+1

यह समझाने के लिए अच्छा हो सकता है? –

+0

शानदार! बिल्कुल मुझे क्या चाहिए। –

4

यहाँ कुछ मैं एक सशर्त अवरोही से निपटने के लिए के साथ आया है। आप गतिशील रूप से keySelector func उत्पन्न करने के अन्य तरीकों के साथ इसे जोड़ सकते हैं।

public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, 
      System.Linq.Expressions.Expression<Func<TSource, TKey>> keySelector, 
      System.ComponentModel.ListSortDirection sortOrder 
      ) 
    { 
     if (sortOrder == System.ComponentModel.ListSortDirection.Ascending) 
      return source.OrderBy(keySelector); 
     else 
      return source.OrderByDescending(keySelector); 
    } 

उपयोग:

//imagine this is some parameter 
var direction = System.ComponentModel.ListSortDirection.Ascending; 
query = query.OrderBy(ec => ec.MyColumnName, direction); 

सूचना इस श्रृंखला करने की अनुमति देता है किसी भी IQueryable पर एक नया पैरामीटर के साथ इस .OrderBy विस्तार।

// perhaps passed in as a request of user to change sort order 
// var direction = System.ComponentModel.ListSortDirection.Ascending; 
query = context.Orders 
     .Where(o => o.Status == OrderStatus.Paid) 
     .OrderBy(ec => ec.OrderPaidUtc, direction); 
1

एकमात्र समाधान है कि काम के लिए मुझे यहाँ https://gist.github.com/neoGeneva/1878868 neoGeneva द्वारा पोस्ट किया गया।

मैं अपना कोड दोबारा पोस्ट करूंगा क्योंकि यह अच्छी तरह से काम करता है और मैं नहीं चाहता कि यह इंटरवब्स में खो जाए!

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortExpression) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source", "source is null."); 

     if (string.IsNullOrEmpty(sortExpression)) 
      throw new ArgumentException("sortExpression is null or empty.", "sortExpression"); 

     var parts = sortExpression.Split(' '); 
     var isDescending = false; 
     var propertyName = ""; 
     var tType = typeof(T); 

     if (parts.Length > 0 && parts[0] != "") 
     { 
      propertyName = parts[0]; 

      if (parts.Length > 1) 
      { 
       isDescending = parts[1].ToLower().Contains("esc"); 
      } 

      PropertyInfo prop = tType.GetProperty(propertyName); 

      if (prop == null) 
      { 
       throw new ArgumentException(string.Format("No property '{0}' on type '{1}'", propertyName, tType.Name)); 
      } 

      var funcType = typeof(Func<,>) 
       .MakeGenericType(tType, prop.PropertyType); 

      var lambdaBuilder = typeof(Expression) 
       .GetMethods() 
       .First(x => x.Name == "Lambda" && x.ContainsGenericParameters && x.GetParameters().Length == 2) 
       .MakeGenericMethod(funcType); 

      var parameter = Expression.Parameter(tType); 
      var propExpress = Expression.Property(parameter, prop); 

      var sortLambda = lambdaBuilder 
       .Invoke(null, new object[] { propExpress, new ParameterExpression[] { parameter } }); 

      var sorter = typeof(Queryable) 
       .GetMethods() 
       .FirstOrDefault(x => x.Name == (isDescending ? "OrderByDescending" : "OrderBy") && x.GetParameters().Length == 2) 
       .MakeGenericMethod(new[] { tType, prop.PropertyType }); 

      return (IQueryable<T>)sorter 
       .Invoke(null, new object[] { source, sortLambda }); 
     } 

     return source; 
    } 
4

1) स्थापित करें System.Linq.Dynamic

2) निम्नलिखित कोड

public static class OrderUtils 
{ 
    public static string ToStringForOrdering<T, TKey>(this Expression<Func<T, TKey>> expression, bool isDesc = false) 
    { 
     var str = expression.Body.ToString(); 
     var param = expression.Parameters.First().Name; 
     str = str.Replace("Convert(", "(").Replace(param + ".", ""); 
     return str + (isDesc ? " descending" : ""); 
    } 
} 

3) लैम्ब्डा समारोह

public static class SortHelper 
{ 
    public static Expression<Func<UserApp, object>> UserApp(string orderProperty) 
    { 
     orderProperty = orderProperty?.ToLowerInvariant(); 
     switch (orderProperty) 
     { 
      case "firstname": 
       return x => x.PersonalInfo.FirstName; 
      case "lastname": 
       return x => x.PersonalInfo.LastName; 
      case "fullname": 
       return x => x.PersonalInfo.FirstName + x.PersonalInfo.LastName; 
      case "email": 
       return x => x.Email; 

     } 
    } 
} 

4 के चयन के लिए अपने स्विच लिखें जोड़े) अपने सहायकों का प्रयोग करें

Dbset.OrderBy(SortHelper.UserApp("firstname").ToStringForOrdering()) 

5) आप pagging (PagedList)

public virtual IPagedList<T> GetPage<TOrder>(Page page, Expression<Func<T, bool>> where, Expression<Func<T, TOrder>> order, bool isDesc = false, 
     params Expression<Func<T, object>>[] includes) 
    { 
     var orderedQueryable = Dbset.OrderBy(order.ToStringForOrdering(isDesc)); 
     var query = orderedQueryable.Where(where).GetPage(page); 
     query = AppendIncludes(query, includes); 

     var results = query.ToList(); 
     var total = Dbset.Count(where); 

     return new StaticPagedList<T>(results, page.PageNumber, page.PageSize, total); 
    } 

स्पष्टीकरण के साथ उपयोग कर सकते हैं

System.Linq.Dynamic हमें OrderBy विधि में स्ट्रिंग मान सेट करने के लिए अनुमति देता है। लेकिन इस विस्तार के अंदर स्ट्रिंग को लैम्ब्डा को पार्स किया जाएगा। तो मैंने सोचा कि यह काम करेगा अगर हम लैम्बडा को स्ट्रिंग करने और ऑर्डरबी विधि को देने के लिए पार्स करेंगे। और यह काम करता है!

0

मैं पार्टी के लिए देर से हूं लेकिन इनमें से कोई भी समाधान मेरे लिए काम नहीं करता है। मैं System.Linq.Dynamic की कोशिश करने के लिए उत्सुक था, लेकिन मुझे यह Nuget पर नहीं मिला, शायद अवमूल्यन? किसी भी तरह से ...

यहां एक समाधान है जिसके साथ मैं आया हूं। मुझे गतिशील रूप से ऑर्डरबी, ऑर्डरबैडस्केंडिंग और ऑर्डरबी> फिर के मिश्रण का उपयोग करने की आवश्यकता है।

मैं बस मेरी सूची में वस्तु, hacky थोड़ा मैं जानता हूँ कि के लिए एक विस्तार विधि बनाया ... मैं इस की सिफारिश नहीं होगा अगर यह कुछ मैं का एक बहुत कुछ कर रहा था थे, लेकिन यह एक एक बंद के लिए अच्छा है।

List<Employee> Employees = GetAllEmployees(); 

foreach(Employee oEmployee in Employees.ApplyDynamicSort(eEmployeeSort)) 
{ 
    //do stuff 
} 

public static IOrderedEnumerable<Employee> ApplyDynamicSort(this List<Employee> lEmployees, Enums.EmployeeSort eEmployeeSort) 
{ 
    switch (eEmployeeSort) 
    { 
     case Enums.EmployeeSort.Name_ASC: 
      return lEmployees.OrderBy(x => x.Name); 
     case Enums.EmployeeSort.Name_DESC: 
      return lEmployees.OrderByDescending(x => x.Name); 
     case Enums.EmployeeSort.Department_ASC_Salary_DESC: 
      return lEmployees.OrderBy(x => x.Department).ThenByDescending(y => y.Salary); 
     default: 
      return lEmployees.OrderBy(x => x.Name); 
    } 
} 
0
  • डला पैकेज अपने कोड

  • को डायनामाइट जोड़ें नाम स्थान Dynamite.Extensions जोड़े उदाहरण के लिए: Dynamite.Extensions उपयोग करते हुए;

  • किसी भी SQL क्वेरी जैसे क्वेरी द्वारा ऑर्डर दें: छात्र.ऑर्डर बी ("सिटी डीईएससी, पता")। ToList();

0

answer by @Icarus पर विस्तार करने के लिए: अगर आप एक्सटेंशन विधि की वापसी प्रकार चाहते हैं एक IQueryable के बजाय एक IOrderedQueryable होने के लिए, आप बस परिणाम इस प्रकार डाली कर सकते हैं:

public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc) 
{ 
    string command = desc ? "OrderByDescending" : "OrderBy"; 
    var type = typeof(TEntity); 
    var property = type.GetProperty(orderByProperty); 
    var parameter = Expression.Parameter(type, "p"); 
    var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
    var orderByExpression = Expression.Lambda(propertyAccess, parameter); 
    var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType }, 
     source.Expression, Expression.Quote(orderByExpression)); 
    return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression); 
} 
संबंधित मुद्दे