मैं एक सामान्य एक्सटेंशन विधि के भीतर एक स्ट्रिंग कॉलम नाम का उपयोग करके एक IQueryable पर ऑर्डरबाय कैसे लागू कर सकता हूं?


85
public static IQueryable<TResult> ApplySortFilter<T, TResult>(this IQueryable<T> query, string columnName)
  where T : EntityObject
{
  var param = Expression.Parameter(typeof(T), "o");
  var body = Expression.PropertyOrField(param,columnName);

  var sortExpression = Expression.Lambda(body, param);
  return query.OrderBy(sortExpression);
}

क्योंकि ऑर्डरबाय के लिए टाइप सॉर्ट एक्सप्रेशन से अनुमानित नहीं है, मुझे इसे रन टाइम में इस तरह से निर्दिष्ट करने की आवश्यकता है:

var sortExpression = Expression.Lambda<T, TSortColumn>(body, param);

या

return query.OrderBy<T, TSortColumn>(sortExpression);

मुझे नहीं लगता कि यह संभव है, क्योंकि TSortColumn केवल रनटाइम के दौरान निर्धारित किया जा सकता है।

क्या इसके चारों ओर एक रास्ता है?


यकीन नहीं है कि यह क्या आप के लिए देख रहे हैं, लेकिन एक नज़र रखना। चीयर्स
jaopopintocruz

@Jewew मैं क्लॉज द्वारा दूसरा आदेश कैसे लागू कर सकता हूं..आदि क्रम में आईडी फिर तिथि तक
SRJ

जवाबों:


113

हमने LINQ में SQL प्रोजेक्ट के समान (100% समान नहीं, बल्कि समान) कुछ किया। यहाँ कोड है:

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values) {
    var type = typeof(T);
    var property = type.GetProperty(ordering);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);
    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
    return source.Provider.CreateQuery<T>(resultExp);
}

हमने वास्तव में एक जेनेरिक का उपयोग नहीं किया था, हमारे पास एक ज्ञात वर्ग था, लेकिन इसे एक जेनेरिक पर काम करना चाहिए (मैंने जेनेरिक प्लेसहोल्डर को रखा है जहां यह होना चाहिए)।

संपादित करें: अवरोही क्रम के लिए, OrderByDescending"ऑर्डरबाय" के बजाय पास करें :

MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));


1
अवरोही क्रम के लिए, "OrderBy" MethodCallExpression resultExp = Expression.Call (typeof (Queryable), "OrderByDescending" के "OrderByDescending" में पारित बजाय, ...
गैरी अंग्रेजी

3
यह ठीक काम किया है, लेकिन निम्नलिखित सिर्फ एक बहुत अच्छा साफ कोड उदाहरण था: stackoverflow.com/questions/41244/dynamic-linq-orderby
BenSwayne

@ ऐरॉन पॉवेल मैं क्लॉज द्वारा दूसरा ऑर्डर कैसे लागू कर सकता हूं..तो ऑर्डरबी आईडी फिर तारीख तक
SRJ

3
के लिए पैरामीटर क्या है values?
फ्रैंक फजार्डो

31

आप डायनामिक लाइनक का भी उपयोग कर सकते हैं

यहाँ जानकारी http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

सी # यहां डाउनलोड करें http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

तो बस Linq.Dynamic का उपयोग कर जोड़ें; और आपको स्वचालित रूप से 2 अतिरिक्त एक्सटेंशन विधियाँ मिलेंगी जिनका उपयोग इस तरह किया जा सकता है

return query.OrderBy("StringColumnName");

धन्यवाद, मैंने देखा था कि Phil Haack की साइट पर एक नमूने में Linq.Dynamic था लेकिन इसके बारे में अनिश्चित था। मैं सप्ताहांत में इसके साथ एक नाटक करूंगा।
जेटीव

एक विकल्प के रूप में Systems.Linq.Dynamic.dll को यहां से डाउनलोड किया जा सकता है: github.com/kahanu/System.Linq.Dynamic
Baig

12

मैंने चाइल्ड प्रॉपर्टीज़ के लिए समर्थन जोड़ने के लिए आपके कार्यों को बढ़ाया है।

private static LambdaExpression GenerateSelector<TEntity>(String propertyName, out Type resultType) where TEntity : class
{
    // Create a parameter to pass into the Lambda expression (Entity => Entity.OrderByField).
    var parameter = Expression.Parameter(typeof(TEntity), "Entity");
    //  create the selector part, but support child properties
    PropertyInfo property;
    Expression propertyAccess;
    if (propertyName.Contains('.'))
    {
            // support to be sorted on child fields.
            String[] childProperties = propertyName.Split('.');
            property = typeof(TEntity).GetProperty(childProperties[0]);
            propertyAccess = Expression.MakeMemberAccess(parameter, property);
            for (int i = 1; i < childProperties.Length; i++)
            {
                    property = property.PropertyType.GetProperty(childProperties[i]);
                    propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
            }
    }
    else
    {
            property = typeof(TEntity).GetProperty(propertyName);
            propertyAccess = Expression.MakeMemberAccess(parameter, property);
    }
    resultType = property.PropertyType;                     
    // Create the order by expression.
    return Expression.Lambda(propertyAccess, parameter);
}

private static MethodCallExpression GenerateMethodCall<TEntity>(IQueryable<TEntity> source, string methodName, String fieldName) where TEntity : class
{
    Type type = typeof(TEntity);
    Type selectorResultType;
    LambdaExpression selector = GenerateSelector<TEntity>(fieldName, out selectorResultType);
    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
                                    new Type[] { type, selectorResultType },
                                    source.Expression, Expression.Quote(selector));
    return resultExp;
}

आप इन कार्यों का उपयोग कर सकते हैं जैसे:

GenerateMethodCall<TEntity>(source, "OrderByDescending", fieldName);

1
आप मेरे हीरो हैं !!
सेबेस्टियन गुरेरो

1
समझदार लोगों को प्यार करेंगे
रॉड जॉन

मैंने इस कोड की कोशिश की और यह एक बच्चे के साथ काम करता है, लेकिन एक से अधिक के साथ नहीं, उदाहरण के लिए यह x.String और x.Object.String पर छंटनी के साथ काम करता है, लेकिन x.Object.Object.String पर छंटनी के साथ नहीं।
रॉबर्ट राबर्ट

8

मैंने ऑर्डरबी के लिए एक्सटेंशन विधि के लिए आपके विचार का उपयोग किया। लेकिन "कई से कई" के मामले में मुझे त्रुटि मिल रही है। उदाहरण के लिए आपके पास टेबल साइट, ग्राहक और ग्राहक_साइट है। दी गई साइट के लिए मैं ग्राहक के नाम और ऑर्डरबाय एक्सटेंशन (जब मैं "site.customer" पास करता हूं, जहां ग्राहक नेविगेशन प्रॉपर्टी है) को सॉर्ट करना चाहता हूं। मुझे लाइन में त्रुटि मिलती है: propertyAccess = Expression.MakeMemberAccess (संपत्ति, संपत्ति, संपत्ति);

यह वही है जो मैं उपयोग करता हूं (कुछ वृद्धि के साथ :-)):

public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByValues) where TEntity : class
{
  IQueryable<TEntity> returnValue = null;

  string orderPair = orderByValues.Trim().Split(',')[0];
  string command = orderPair.ToUpper().Contains("DESC") ? "OrderByDescending" : "OrderBy";

  var type = typeof(TEntity);
  var parameter = Expression.Parameter(type, "p");

  string propertyName = (orderPair.Split(' ')[0]).Trim();

  System.Reflection.PropertyInfo property;
  MemberExpression propertyAccess;

  if (propertyName.Contains('.'))
  {
    // support to be sorted on child fields. 
    String[] childProperties = propertyName.Split('.');
    property = typeof(TEntity).GetProperty(childProperties[0]);
    propertyAccess = Expression.MakeMemberAccess(parameter, property);

    for (int i = 1; i < childProperties.Length; i++)
    {
      Type t = property.PropertyType;
      if (!t.IsGenericType)
      {
        property = t.GetProperty(childProperties[i]);
      }
      else
      {
        property = t.GetGenericArguments().First().GetProperty(childProperties[i]);
      }

      propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
    }
  }
  else
  {
    property = type.GetProperty(propertyName);
    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));

  returnValue = source.Provider.CreateQuery<TEntity>(resultExpression);

  if (orderByValues.Trim().Split(',').Count() > 1)
  {
    // remove first item
    string newSearchForWords = orderByValues.ToString().Remove(0, orderByValues.ToString().IndexOf(',') + 1);
    return source.OrderBy(newSearchForWords);
  }

  return returnValue;
}

सादर

स्लोबोदान


6

ऐसा लगता है कि यह ऐसा करने का तरीका है, अब इसे सत्यापित करने के लिए:

// ***** OrderBy(company => company) *****
// Create an expression tree that represents the expression
// 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderByCallExpression = Expression.Call(
    typeof(Queryable),
    "OrderBy",
    new Type[] { queryableData.ElementType, queryableData.ElementType },
    whereCallExpression,
    Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));
// ***** End OrderBy *****

1
लानत है, 34 सेकंड पीछे! : पी
आरोन पॉवेल

3

यदि आप "System.Linq.Dynamic" पैकेज को जोड़ने में सक्षम हैं, तो बिना किसी जटिलता के बहुत आसान है,

fisrt insatll पैकेज "System.Linq.Dynamic" NuGet पैकेज मैनेजर से तो अपनी जरूरत के अनुसार नीचे की कोशिश करें,

उदाहरण के लिए:

public IQueryable<TEntity> GetWithInclude(Expression<Func<TEntity, bool>> predicate,
                    List<string> sortBy, int pageNo, int pageSize = 12, params string[] include)
        {
            try
            {
                var numberOfRecordsToSkip = pageNo * pageSize;
                var dynamic = DbSet.AsQueryable();

                foreach (var s in include)
                {
                    dynamic.Include(s);
                }
                 return dynamic.OrderBy("CreatedDate").Skip(numberOfRecordsToSkip).Take(pageSize);


            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

आशा है कि यह मदद करेगा


2

मैंने इस कोड को थोड़ा तय किया: https://stackoverflow.com/a/1670085/5852630

यह कोड अनुक्रमिक छँटाई के साथ काम करता है: पहले "ऑर्डरबाय", फिर "तबबाई" (न कि "ऑर्डरबीबी"!) निष्पादित करें।

public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByValues) where TEntity : class
{
    IQueryable<TEntity> returnValue = null;

    string[] orderPairs = orderByValues.Trim().Split(',');

    Expression resultExpression = source.Expression;

    string strAsc = "OrderBy";
    string strDesc = "OrderByDescending";

    foreach (string orderPair in orderPairs)
    {
        if (string.IsNullOrWhiteSpace(orderPair))
            continue;

        string[] orderPairArr = orderPair.Trim().Split(' ');

        string propertyName = orderPairArr[0].Trim();
        string orderNarrow = orderPairArr.Length > 1 ? orderPairArr[1].Trim() : string.Empty;

        string command = orderNarrow.ToUpper().Contains("DESC") ? strDesc : strAsc;

        Type type = typeof(TEntity);
        ParameterExpression parameter = Expression.Parameter(type, "p");

        System.Reflection.PropertyInfo property;
        Expression propertyAccess;

        if (propertyName.Contains('.'))
        {
            // support to be sorted on child fields. 
            String[] childProperties = propertyName.Split('.');
            property = typeof(TEntity).GetProperty(childProperties[0]);
            propertyAccess = Expression.MakeMemberAccess(parameter, property);

            for (int i = 1; i < childProperties.Length; i++)
            {
                Type t = property.PropertyType;
                if (!t.IsGenericType)
                {
                    property = t.GetProperty(childProperties[i]);
                }
                else
                {
                    property = t.GetGenericArguments().First().GetProperty(childProperties[i]);
                }

                propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
            }
        }
        else
        {
            property = type.GetProperty(propertyName);
            propertyAccess = Expression.MakeMemberAccess(parameter, property);
        }

        if (property.PropertyType == typeof(object))
        {
            propertyAccess = Expression.Call(propertyAccess, "ToString", null);
        }

        LambdaExpression orderByExpression = Expression.Lambda(propertyAccess, parameter);

        resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType == typeof(object) ? typeof(string) : property.PropertyType },
            resultExpression, Expression.Quote(orderByExpression));

        strAsc = "ThenBy";
        strDesc = "ThenByDescending";
    }

    returnValue = source.Provider.CreateQuery<TEntity>(resultExpression);

    return returnValue;
}

0

यहाँ @Davy Landman के उत्तर से मेरा अनुकूलन है (मैं एक विस्तार विधि चाहता था) और मैंने थोड़ा सरल किया।

public static IQueryable<T> SortBy<T>(this IQueryable<T> source, 
                                      String propertyName, 
                                      WebControls.SortDirection direction)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (String.IsNullOrEmpty(propertyName)) return source;

        // Create a parameter to pass into the Lambda expression
        //(Entity => Entity.OrderByField).
        var parameter = Expression.Parameter(typeof(T), "Entity");

        //  create the selector part, but support child properties (it works without . too)
        String[] childProperties = propertyName.Split('.');
        MemberExpression property = Expression.Property(parameter, childProperties[0]);
        for (int i = 1; i < childProperties.Length; i++)
        {
            property = Expression.Property(property, childProperties[i]);
        }

        LambdaExpression selector = Expression.Lambda(property, parameter);

        string methodName = (direction > 0) ? "OrderByDescending" : "OrderBy";

        MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
                                        new Type[] { source.ElementType, property.Type },
                                        source.Expression, Expression.Quote(selector));

        return source.Provider.CreateQuery<T>(resultExp);
    }

इसका उपयोग इस तरह किया जा सकता है:

gridview1.DataSource = DbContext.TB_CARS.SortBy("model", SortDirection.Descending);
//OR
gridview1.DataSource = DbContext.TB_CARS.SortBy("owner.first_name", 0);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.