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




linq-to-objects (12)

आप IEUumerable को IQueryable में परिवर्तित कर सकते हैं।

items = items.AsQueryable().OrderBy("Name ASC");

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


आप इसे जोड़ सकते हैं:

public static IEnumerable<T> OrderBy( this IEnumerable<T> input, string queryString) {
    //parse the string into property names
    //Use reflection to get and sort by properties
    //something like

    foreach( string propname in queryString.Split(','))
        input.OrderBy( x => GetPropertyValue( x, propname ) );

    // I used Kjetil Watnedal's reflection example
}

GetPropertyValue फ़ंक्शन Kjetil Watnedal के उत्तर से है

मुद्दा क्यों होगा? ऐसा कोई भी प्रकार समय संकलित करने के बजाए रन-टाइम पर अपवाद फेंक देगा (जैसे डी 2VIANT का जवाब)।

यदि आप लिंक से एसक्यूएल से निपट रहे हैं और ऑर्डरबी एक अभिव्यक्ति वृक्ष है तो इसे निष्पादन के लिए SQL में परिवर्तित कर दिया जाएगा।


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

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;
}

पहले गतिशील उपकरण स्थापित करें -> NuGet पैकेज प्रबंधक -> पैकेज प्रबंधक कंसोल

install-package System.Linq.Dynamic

using System.Linq.Dynamic; नेमस्पेस जोड़ें using System.Linq.Dynamic;

अब आप OrderBy("Name, Age DESC") उपयोग कर सकते हैं


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

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

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

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


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

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

मार्टन के लिए धन्यवाद ( LINQ में PropertyInfo ऑब्जेक्ट का उपयोग करके संग्रह संग्रह करें ) मुझे यह समाधान मिला:

myList.OrderByDescending(x => myPropertyInfo.GetValue(x, null)).ToList();

मेरे मामले में मैं "कॉलमहेडर मूसक्लिक" (विंडोजफॉर्म) पर काम कर रहा था इसलिए बस विशिष्ट कॉलम दबाया गया और इसके संवाददाता PropertyInfo:

foreach (PropertyInfo column in (new Process()).GetType().GetProperties())
{
    if (column.Name == dgvProcessList.Columns[e.ColumnIndex].Name)
    {}
}

या

PropertyInfo column = (new Process()).GetType().GetProperties().Where(x => x.Name == dgvProcessList.Columns[e.ColumnIndex].Name).First();

(सुनिश्चित करें कि ऑब्जेक्ट गुणों से मेल खाने वाले आपके कॉलम नाम हों)

चियर्स


मुझे जवाब मिला। मैं अपनी सूची को IQueryable में बदलने के लिए .AsQueryable<>() एक्सटेंशन विधि का उपयोग कर सकता हूं, फिर इसके विरुद्ध गतिशील क्रम चलाएं।


मैं ऐसा करने की कोशिश कर रहा था लेकिन 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() के लिए कोड के लिए यह पोस्ट देखें।


मैंने इस प्रश्न को ठोकर दिया है कि लिंकक एकाधिक ऑर्डरबॉजी क्लॉज की तलाश है और शायद यही वह लेखक था जिसे लेखक ढूंढ रहे थे

यहां ऐसा करने का तरीका बताया गया है:

var query = pets.OrderBy(pet => pet.Name).ThenByDescending(pet => pet.Age);    

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

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

सूची को IENumerable या Iquerable में कनवर्ट करें, System.LINQ.Dynamic नेमस्पेस का उपयोग करके जोड़ें, फिर आप ऑर्डरबी विधि में अल्पविराम सेपरेटेड स्ट्रिंग में प्रॉपर्टी नामों का उल्लेख कर सकते हैं जो System.LINQ.Dynamic से डिफ़ॉल्ट रूप से आता है।





linq-to-objects