Come applicare OrderBy su un IQueryable utilizzando un nome di colonna stringa all’interno di un metodo di estensione generico?

public static IQueryable ApplySortFilter(this IQueryable 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); } 

Poiché il tipo per OrderBy non viene dedotto da sortExpression, è necessario specificarlo in questo modo in fase di esecuzione:

 var sortExpression = Expression.Lambda(body, param); 

O

 return query.OrderBy(sortExpression); 

Non penso che sia ansible, tuttavia, poiché TSortColumn può essere determinato solo durante il runtime.

C’è un modo per aggirare questo?

Abbiamo fatto qualcosa di simile (non uguale al 100%, ma simile) in un progetto LINQ to SQL. Ecco il codice:

 public static IQueryable OrderBy(this IQueryable 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(resultExp); } 

In realtà non usavamo un generico, avevamo una class nota, ma dovrebbe funzionare su un generico (ho messo il segnaposto generico dove dovrebbe essere).

Modifica: per ordine decrescente, passa in OrderByDescending invece di “OrderBy”:

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

Puoi anche utilizzare Dynamic Linq

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

Scarica C # qui http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Quindi basta aggiungere l’uso di Linq.Dynamic; e ottieni automaticamente 2 ulteriori metodi di estensione che possono essere usati in questo modo

 return query.OrderBy("StringColumnName"); 

Ho esteso le tue funzioni per aggiungere supporto per Proprietà figlio.

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

Puoi usare queste funzioni come:

 GenerateMethodCall(source, "OrderByDescending", fieldName); 

Ho usato la tua idea per il metodo di estensione per OrderBy. Ma in caso di “molti a molti” sto ricevendo errore. Ad esempio, hai sito tabella, cliente e sito cliente. Per il sito dato voglio ordinare per nome cliente e in estensione OrderBy (quando passo “site.customer” dove cliente è proprietà di navigazione) ottengo errore in linea: propertyAccess = Expression.MakeMemberAccess (propertyAccess, proprietà);

Questo è quello che uso (con alcuni miglioramenti :-)):

 public static IQueryable OrderBy(this IQueryable source, string orderByValues) where TEntity : class { IQueryable 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(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; } 

Saluti

Slobodan

Sembra che questo sia il modo per farlo, ora per verificare che:

 // ***** 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>(pe, new ParameterExpression[] { pe })); // ***** End OrderBy ***** 

Se si è in grado di aggiungere il pacchetto “System.Linq.Dynamic” allora, troppo semplice senza alcuna complicazione,

pacchetto completo insatll “System.Linq.Dynamic” dal gestore pacchetti NuGet quindi provare come di seguito come il vostro bisogno,

Ex:

 public IQueryable GetWithInclude(Expression> predicate, List 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); } } 

Spero che questo ti sia d’aiuto

Ho risolto un po ‘questo codice: https://stackoverflow.com/a/1670085/5852630

Questo codice funziona con l’ordinamento sequenziale: prima eseguire “OrderBy”, quindi “ThenBy” (non “OrderBy”!)

 public static IQueryable OrderBy(this IQueryable source, string orderByValues) where TEntity : class { IQueryable 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(resultExpression); return returnValue; }