Soru Bir genel uzantı yönteminde bir dize sütun adı kullanarak OrderBy'yi bir IQueryable üzerinde nasıl uygularım?


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

OrderBy türünün sortExpression türünden çıkarılmaması nedeniyle, çalışma zamanında buna benzer bir şey belirtmem gerekiyor:

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

Veya

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

Ancak bunun mümkün olduğunu düşünmüyorum ancak TSortColumn sadece çalışma sırasında belirlenebilir.

Bunun etrafında bir yolu var mı?


76
2017-11-21 01:15


Menşei


Olduğundan emin değilim bu Ne arıyorsun ama bak. Şerefe - joaopintocruz
@JTew İkinci bir siparişi nasıl uygulayabilirim? - SRJ


Cevaplar:


LINQ to SQL projesinde benzer bir şey (% 100 aynı değil, benzer) yaptık. İşte kod:

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

Aslında bir jenerik kullanmadık, bilinen bir sınıfa sahiptik, ama bir jenerik üzerinde çalışmalı (genel yer tutucuyu olması gereken yere koydum).

Düzenle: Azalan sipariş için, içeri aktar OrderByDescending "OrderBy" yerine:

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

102
2017-11-21 02:01



Sorun yok, cevabını zaten kendime atayamam :) - JTew
azalan düzen için, "OrderByDescending" yerine "OrderByDescending" yöntemine geçin. YöntemDeğişim sonucuExp = Expression.Call (typeof (Queryable), "OrderByDescending", ... - Garry English
Bu sadece iyi çalıştı, ama aşağıdaki gerçekten güzel bir temiz kod örneğiydi: stackoverflow.com/questions/41244/dynamic-linq-orderby - BenSwayne
@Aaron Powell İkinci bir siparişi nasıl uygulayabilirim? - SRJ
Parametre nedir values için? - Frank Fajardo


Dinamik Linq'i de kullanabilirsiniz

Bilgi burada http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

C # buradan indirin http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Sonra sadece Linq.Dynamic kullanarak ekleyin; ve bu şekilde kullanılabilecek 2 ek uzantı yöntemini otomatik olarak alıyorsunuz

return query.OrderBy("StringColumnName");

27
2018-05-12 16:17



Teşekkürler, Phil Haack'ın sitesinde bir örnekte Linq.Dynamic'i görmüştüm ama bu konuda emin değildim. Hafta sonu boyunca bununla bir oyun oynayacağım. - JTew
Alternatif olarak Systems.Linq.Dynamic.dll buradan indirilebilir: github.com/kahanu/System.Linq.Dynamic - Baig


Çocuk Özellikleri için destek eklemek için işlevlerinizi genişlettim.

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

Bu işlevleri aşağıdaki gibi kullanabilirsiniz:

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

10
2017-11-21 14:00



Kahramanımsın !! - Sebastián Guerrero
akıllı insanları sevmeliyim - Rod Johnson


OrderBy için uzatma yöntemi fikrini kullandım. Ama "çoktan fazlası" durumunda hata alıyorum. Örneğin, tablo Site, Müşteri ve Customer_site var. Verilen Site için müşteri ismine ve OrderBy uzantısına göre sıralamak istiyorum (müşteri navigasyon özelliğinin bulunduğu site.customer adresini geçtiğimde) Hata satırına geçiyorum: propertyAccess = Expression.MakeMemberAccess (propertyAccess, property);

Kullandığım şey (bazı geliştirmelerle :-)):

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

Saygılarımızla

Slobodan


8
2017-11-03 20:56





Öyle görünüyor bu Bunu yapmanın yolu, şimdi doğrulamak için:

// ***** 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 *****

6
2017-11-21 02:00



lanet, 34 saniye geride! : P - Aaron Powell


"System.Linq.Dynamic" paketini ekleyebiliyorsanız, Herhangi bir komplikasyon olmaksızın çok kolay,

NuGet paket yöneticisinden fisrt insatll paketi "System.Linq.Dynamic" İhtiyacınız olan aşağıdaki gibi deneyin,

Ör:

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

Umarım bu yardımcı olur


2
2018-02-12 17:42





Bu kodu biraz düzeltdim: https://stackoverflow.com/a/1670085/5852630

Bu kod sıralı sıralama ile çalışır: önce "OrderBy", sonra "ThenBy" (Not "OrderBy" değil!)

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

1
2018-05-04 13:01