[c#] ديناميكية LINQ OrderBy على IEnumerable <T>


Answers

سهل للغاية دون أي تعقيد:

  1. إضافة using System.Linq.Dynamic; في القمة.
  2. استخدام vehicles = vehicles.AsQueryable().OrderBy("Make ASC, Year DESC").ToList();
Question

لقد وجدت مثالاً في أمثلة VS2008 لـ LINQ الديناميكي الذي يسمح لك باستخدام سلسلة تشبه SQL (على سبيل المثال OrderBy("Name, Age DESC")) للطلب. لسوء الحظ ، فإن الطريقة شملت تعمل فقط على IQueryable<T> ؛ هل هناك أي طريقة للحصول على هذه الوظيفة على IEnumerable<T> ؟




هنا شيء آخر وجدت مثيرة للاهتمام. إذا كان المصدر الخاص بك هو DataTable ، فيمكنك استخدام الفرز الديناميكي دون استخدام Dynamic Linq

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 (باستخدام DataSetExtensions)

فيما يلي طريقة أخرى للقيام بذلك عن طريق تحويله إلى DataView:

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






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



كنت أحاول أن أفعل ذلك ولكن لدي مشاكل مع حل Kjetil Watnedal لأنني لا أستخدم تركيب linq المضمن - أنا أفضل أسلوب بناء الجملة. كانت مشكلتي محددة في محاولة القيام بالفرز الديناميكي باستخدام 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"

يبدو أن OrderBy الديناميكي على النحو التالي:

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




فقط بناء على ما قاله الآخرون. لقد وجدت أن الأعمال التالية جيدة للغاية.

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



هذه الإجابة هي رد على التعليقات التي تحتاج إلى مثال للحل المقدم من John Sheehan - Runscope

يرجى تقديم مثال لبقيتنا.

في DAL (طبقة الوصول إلى البيانات) ،

إصدار 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 للربط ، على سبيل المثال GridView في Asp.net والاستفادة من الفرز (لا يمكنك فرز باستخدام إصدار IEnumerable)

اعتدت Dapper كما ORM وبناء نسخة IQueryable والفرز المستخدمة في GridView في asp.net سهلة للغاية.




بعد الكثير من البحث ، عمل هذا من أجلي:

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



Related