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




linq-to-objects (16)

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


Answers

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

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() के लिए कोड के लिए यह पोस्ट देखें।


मार्टन के लिए धन्यवाद ( 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();

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

चियर्स


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


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

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

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

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 संस्करण का निर्माण किया और एस्पनेट में ग्रिड व्यू में सॉर्टिंग का उपयोग इतना आसान बना दिया।


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

ऊपर से मार्क के 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);
}

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

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

install-package System.Linq.Dynamic

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

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


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

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

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


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

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 में परिवर्तित कर दिया जाएगा।


मुझे लगता है कि यह जो भी संपत्ति आप सॉर्ट करना चाहते हैं उसे प्राप्त करने के लिए प्रतिबिंब का उपयोग करने के लिए काम करेगी:

IEnumerable<T> myEnumerables
var query=from enumerable in myenumerables
          where some criteria
          orderby GetPropertyValue(enumerable,"SomeProperty")
          select enumerable

private static object GetPropertyValue(object obj, string property)
{
    System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
    return propertyInfo.GetValue(obj, null);
}

ध्यान दें कि प्रतिबिंब का उपयोग सीधे संपत्ति तक पहुंचने से काफी धीमा है, इसलिए प्रदर्शन की जांच करनी होगी।


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

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

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

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

String.Concat और Enumerable.Repeat का उपयोग करना। String.Concat जो String.Join का उपयोग करने से कम महंगा होगा

public static Repeat(this String pattern, int count)
{
    return String.Concat(Enumerable.Repeat(pattern, count));
}






c# linq linq-to-objects