[c#] डायनेमिक LINQ ऑर्डर INumerable <T> पर



8 Answers

बिना किसी जटिलता के बहुत आसान:

  1. using System.Linq.Dynamic; जोड़ें using System.Linq.Dynamic; शीर्ष पर।
  2. vehicles = vehicles.AsQueryable().OrderBy("Make ASC, Year DESC").ToList(); उपयोग करें vehicles = vehicles.AsQueryable().OrderBy("Make ASC, Year DESC").ToList();
Question

मुझे डायनेमिक LINQ के लिए VS2008 उदाहरणों में एक उदाहरण मिला जो आपको ऑर्डर करने के लिए एक एसक्यूएल-जैसी स्ट्रिंग (उदाहरण के लिए OrderBy("Name, Age DESC")) का उपयोग करने की अनुमति देता है। दुर्भाग्य से, विधि शामिल केवल IQueryable<T> ; पर काम करता है। क्या इस कार्यक्षमता को IEnumerable<T> पर प्राप्त करने का कोई तरीका है?




var result1 = lst.OrderBy(a=>a.Name);// for ascending order. 
 var result1 = lst.OrderByDescending(a=>a.Name);// for desc order. 



एक वैकल्पिक समाधान निम्न वर्ग / इंटरफ़ेस का उपयोग करता है। यह वास्तव में गतिशील नहीं है, लेकिन यह काम करता है।

public interface IID
{
    int ID
    {
        get; set;
    }
}

public static class Utils
{
    public static int GetID<T>(ObjectQuery<T> items) where T:EntityObject, IID
    {
        if (items.Count() == 0) return 1;
        return items.OrderByDescending(u => u.ID).FirstOrDefault().ID + 1;
    }
}



बहुत सारी खोजों के बाद यह मेरे लिए काम किया:

public static IEnumerable<TEntity> OrderBy<TEntity>(this IEnumerable<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, property.PropertyType },
                                           source.AsQueryable().Expression, 
                                           Expression.Quote(orderByExpression));
    return source.AsQueryable().Provider.CreateQuery<TEntity>(resultExpression);
}



यह उत्तर उन टिप्पणियों का उत्तर है जिन्हें @ जॉन शीहन - रनस्कोप द्वारा प्रदान किए गए समाधान के लिए एक उदाहरण की आवश्यकता है

कृपया हमारे बाकी के लिए एक उदाहरण प्रदान करें।

डीएएल (डेटा एक्सेस लेयर) में,

IENumerable संस्करण:

  public  IEnumerable<Order> GetOrders()
    {
      // i use Dapper to return IEnumerable<T> using Query<T>
      //.. do stuff
      return  orders  // IEnumerable<Order>
  }

IQueryable संस्करण

  public IQueryable<Order> GetOrdersAsQuerable()
    {
        IEnumerable<Order> qry= GetOrders();
        //use the built-in extension method  AsQueryable in  System.Linq namespace
        return qry.AsQueryable();            
    }

अब आप बाध्य करने के लिए IQueryable संस्करण का उपयोग कर सकते हैं, उदाहरण के लिए Asp.net में ग्रिड व्यू और सॉर्टिंग के लिए लाभ (आप IENumerable संस्करण का उपयोग करके सॉर्ट नहीं कर सकते हैं)

मैंने ओआरएम के रूप में डैपर का उपयोग किया और IQueryable संस्करण का निर्माण किया और एस्पनेट में ग्रिड व्यू में सॉर्टिंग का उपयोग इतना आसान बना दिया।




यहां कुछ और है जो मुझे दिलचस्प लगता है। यदि आपका स्रोत डेटाटेबल है, तो आप गतिशील लिंक का उपयोग किये बिना गतिशील सॉर्टिंग का उपयोग कर सकते हैं

DataTable orders = dataSet.Tables["SalesOrderHeader"];
EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         orderby order.Field<DateTime>("OrderDate")
                                         select order;
DataView view = query.AsDataView();
bindingSource1.DataSource = view;

संदर्भ: http://msdn.microsoft.com/en-us/library/bb669083.aspx (डेटासेट एक्सटेंशन का उपयोग करना)

इसे डेटाव्यू में परिवर्तित करके इसे करने का एक और तरीका यहां दिया गया है:

DataTable contacts = dataSet.Tables["Contact"];    
DataView view = contacts.AsDataView();    
view.Sort = "LastName desc, FirstName asc";    
bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();



मैं ऐसा करने की कोशिश कर रहा था लेकिन Kjetil Watnedal के समाधान के साथ समस्याएं थी क्योंकि मैं इनलाइन लिनक सिंटैक्स का उपयोग नहीं करता - मैं विधि-शैली वाक्यविन्यास पसंद करता हूं। मेरी विशिष्ट समस्या एक कस्टम IComparer का उपयोग करके गतिशील सॉर्टिंग करने की कोशिश में थी।

मेरा समाधान इस तरह समाप्त हुआ:

एक IQueryable क्वेरी को इस प्रकार दिया गया है:

List<DATA__Security__Team> teams = TeamManager.GetTeams();
var query = teams.Where(team => team.ID < 10).AsQueryable();

और रन-टाइम सॉर्ट फ़ील्ड तर्क दिया गया:

string SortField; // Set at run-time to "Name"

गतिशील ऑर्डरबी ऐसा दिखता है:

query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField));

और वह GetReflectedPropertyValue () नामक एक छोटी सहायक विधि का उपयोग कर रहा है:

public static string GetReflectedPropertyValue(this object subject, string field)
{
    object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
    return reflectedValue != null ? reflectedValue.ToString() : "";
}

एक आखिरी बात - मैंने उल्लेख किया कि मैं OrderBy को कस्टम IComparer का उपयोग करना चाहता था - क्योंकि मैं प्राकृतिक सॉर्टिंग करना चाहता था।

ऐसा करने के लिए, मैं बस OrderBy को बदलता हूं:

query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField), new NaturalSortComparer<string>());

NaturalSortComparer() के लिए कोड के लिए यह पोस्ट देखें।




बस इस सवाल पर ठोकर खाई।

ऊपर से मार्क के ApplyOrder कार्यान्वयन का उपयोग करके, मैंने एक एक्सटेंशन विधि को एक साथ थप्पड़ मार दिया जो SQL- जैसे तारों को संभालता है:

list.OrderBy("MyProperty DESC, MyOtherProperty ASC");

विवरण यहां पाया जा सकता है: http://aonnull.blogspot.com/2010/08/dynamic-sql-like-linq-orderby-extension.html




दूसरों ने जो कहा है उस पर बस निर्माण करें। मैंने पाया कि निम्नलिखित बहुत अच्छी तरह से काम करता है।

public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> input, string queryString)
{
    if (string.IsNullOrEmpty(queryString))
        return input;

    int i = 0;
    foreach (string propname in queryString.Split(','))
    {
        var subContent = propname.Split('|');
        if (Convert.ToInt32(subContent[1].Trim()) == 0)
        {
            if (i == 0)
                input = input.OrderBy(x => GetPropertyValue(x, subContent[0].Trim()));
            else
                input = ((IOrderedEnumerable<T>)input).ThenBy(x => GetPropertyValue(x, subContent[0].Trim()));
        }
        else
        {
            if (i == 0)
                input = input.OrderByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
            else
                input = ((IOrderedEnumerable<T>)input).ThenByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
        }
        i++;
    }

    return input;
}



Related